[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n## Bug report for Cloudinary iOS SDK\nBefore proceeding, please update to latest version and test if the issue persists\n\n## Describe the bug in a sentence or two.\n…\n\n## Issue Type (Can be multiple)\n[ ] Build - Can’t install or import the SDK\n[ ] Performance - Performance issues\n[ ] Behaviour - Functions aren’t working as expected (Such as generate URL)\n[ ] Documentation - Inconsistency between the docs and behaviour\n[ ] Other (Specify)\n\n## Steps to reproduce\n… if applicable\n\n## Error screenshots or Stack Trace (if applicable)\n…\n\n## Build/Dependency management\n[ ] Cocoa-Pods\n[ ] Carthage\n[ ] Manual import\n[ ] Other (Specify)\n\n## Is the issue reproducible only on a specific device?\n[ ] No\n[ ] Yes (specify model + iOS version)\n\n## Versions and Libraries (fill in the version numbers)\niOS Cloudinary SDK version - 0.0.0\nOSX (on the dev environment) - 0.0.0 \nXCode - 0.0.0\nSwift - 0.0.0\nTarget iOS - 0.0.0\n\nRepository\nIf possible, please provide a link to a reproducible repository that showcases the problem\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n## Feature request for Cloudinary iOS SDK\n…(If your feature is for other SDKs, please request them there)\n\n## Explain your use case\n… (A high level explanation of why you need this feature)\n\n## Describe the problem you’re trying to solve\n… (A more technical view of what you’d like to accomplish, and how this feature will help you achieve it)\n\n## Do you have a proposed solution?\n… (yes, no? Please elaborate if needed)\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "### Brief Summary of Changes\n<!-- Provide some context as to what was changed, from an implementation standpoint. -->\n\n#### What does this PR address?\n- [ ] GitHub issue (Add reference - #XX)\n- [ ] Refactoring\n- [ ] New feature\n- [ ] Bug fix\n- [ ] Adds more tests\n\n#### Are tests included?\n- [ ] Yes\n- [ ] No\n\n#### Reviewer, please note:\n<!--\nList anything here that the reviewer should pay special attention to. This might\ninclude, for example:\n* Dependence on other PRs\n* Reference to other Cloudinary SDKs\n* Changes that seem arbitrary without further explanations\n-->\n\n#### Checklist:\n<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->\n<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->\n- [ ] My code follows the code style of this project.\n- [ ] My change requires a change to the documentation.\n- [ ] I ran the full test suite before pushing the changes and all the tests pass.\n"
  },
  {
    "path": ".gitignore",
    "content": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n*.DS_Store\n\n## Build generated\nbuild/\nDerivedData/\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata/\n\n## Other\n*.moved-aside\n*.xcuserstate\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n*.dSYM.zip\n*.dSYM\n\n## Playgrounds\ntimeline.xctimeline\nplayground.xcworkspace\n\n# Swift Package Manager\n#\n# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.\n# Packages/\n.build/\n\n# CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control\n#\n# Pods/\n_Pods.xcodeproj\n\n# Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\nExample/Carthage/Checkouts\n\nExample/Carthage/Build\n\n# fastlane\n#\n# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the\n# screenshots whenever they are needed.\n# For more information about the recommended setup visit:\n# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md\n\nfastlane/report.xml\nfastlane/Preview.html\nfastlane/screenshots\nfastlane/test_output\niOSInjectionProject/\n\nCloudinary/Frameworks/CLDCrypto\n\n# Samples\nAppDelegate+config.swift\nExample/Pods/\nExample/Podfile.lock\nExample/Cloudinary.xcworkspace/\n\n"
  },
  {
    "path": ".gitmodules",
    "content": "\n"
  },
  {
    "path": ".swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: objective-c\nos: osx\nbefore_script: >\n  export CLOUDINARY_URL=$(bash tools/get_test_cloud.sh);\n  echo cloud_name: \"$(echo $CLOUDINARY_URL | cut -d'@' -f2)\"\nnotifications:\n  email:\n    recipients:\n      - sdk_developers@cloudinary.com\njobs:\n    - osx_image: xcode12\n      xcode_workspace: Example/Cloudinary.xcworkspace\n      xcode_scheme: travis_public_scheme\n      podfile: Example/Podfile\n      install: pod install --project-directory=Example\n      env: CLOUDINARY_URL=$CLOUDINARY_URL\n      xcode_destination: platform=iOS Simulator,OS=13.0,name=iPhone 8\n    - osx_image: xcode12\n      xcode_workspace: Example/Cloudinary.xcworkspace\n      xcode_scheme: travis_public_scheme\n      podfile: Example/Podfile\n      install: pod install --project-directory=Example\n      env: CLOUDINARY_URL=$CLOUDINARY_URL\n      xcode_destination: platform=iOS Simulator,OS=14.0,name=iPhone 8\n    - osx_image: xcode13.2\n      xcode_workspace: Example/Cloudinary.xcworkspace\n      xcode_scheme: travis_public_scheme\n      podfile: Example/Podfile\n      install: pod install --project-directory=Example\n      env: CLOUDINARY_URL=$CLOUDINARY_URL\n      xcode_destination: platform=iOS Simulator,OS=15.2,name=iPhone 8\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "5.2.5 / 2026-01-08\n==================\n\n* Remove _Pods.xcodeproj\n\n5.2.4 / 2025-11-30\n==================\n\nOther changes\n-------------\n* Fix duration attribute for video analytics \n\n5.2.3 / 2025-08-12\n==================\n\nOther Changes\n-------------\n* Add video analytics duration event\n* Add flush events support to video analytics\n\n5.2.2 / 2025-07-30\n==================\n\nOther Changes\n--------------\n* Fix video analytics duration event\n\n5.2.1 / 2025-06-25\n==================\n\nOther Changes\n--------------\n* Add video analytics as public API\n\n5.2.0 / 2025-06-18\n==================\n\nNew functionality\n-----------------\n* Add support for `auto_chaptering` and `auto_transcription` in Upload API\n* Add extra headers support\n\nOther Changes\n--------------\n* Fix API parameters signature\n\n\n5.1.0 / 2024-09-17\n==================\n\nNew functionality\n-----------------\n* Add video transcode\n* Add auto_chaptering and auto_transcription to Upload API\n\n5.0.0 / 2024-04-14\n==================\n\nBreaking Changes\n----------------\n* Remove CLDURLCache in favor of native URLCache\n* Remove ImageCache\n* Old cache saved to the disk will be purged\n\nNew functionality\n-----------------\n* Add URLCache support for `CLDUIImageVIew`\n\n\n4.7.0 / 2024-03-25\n==================\n\nOther Changes\n-------------\n  * Fix privacy manifest\n  * Fix `CLDVideoPlayer`\n\n\n4.6.0 / 2024-03-12\n==================\n\nNew functionality\n-----------------\n* Add support for `media_metadata`\n\nOther Changes\n-------------\n* Fix video analytics\n\n4.5.0 / 2024-02-18\n==================\n\nOther Changes\n-------------\n  * Add privacy manifest\n\n4.4.0 / 2024-01-15\n==================\n\nOther Changes\n-------------\n  * Update analytics token\n\n4.3.0 / 2023-12-25\n==================\n\nOther Changes\n-------------\n  * Add video player analytics\n\n4.2.0 / 2023-10-12\n==================\n\nOther Changes\n-------------\n  * Update analytics token\n\n4.1.1 / 2023-09-18\n==================\n\nOther Changes\n-------------\n  * Fix analytics import\n\n\n4.1.0 / 2023-08-06\n==================\n\nNew functionality\n-----------------\n  * Add video player widget\n\n4.0.1 / 2023-06-12\n==================\n\nOther changes\n-------------\n  * Fix analytics token prefix\n\n4.0.0 / 2023-05-22\n==================\n\nNew functionality\n-----------------\n  * Turn on `CLDURLCache` on by default\n  \nOther changes\n-------------\n  * Make upload request respect timeout\n\n3.4.0 / 2023-03-12\n==================\n\nNew functionality\n-----------------\n  * Add URLCache support for images\n  * Add tests for explicit and rename\n  \nOther changes\n-------------\n  * Fix warning using `URLCredentialStorage`\n\n3.3.0 / 2022-06-12\n==================\n\nNew functionality\n-----------------\n  * Add support for folder decoupling\n  * Add support for `startOffset` and `endOffset` as expression\n  * Allow to disable b-frames\n  * Send tags as an array\n  * Add support for `originalFilename` upload parameter\n\nOther changes\n-------------\n  * Fix expression normalisation\n\n3.2.1 / 2022-01-11\n==================\n  * Fix `Carthage`\n\n3.2.0 / 2022-01-10\n==================\n\nNew functionality\n-----------------\n  * Add support for `apiKey` argument in Upload API\n  * Add support for `preview` effect\n  \nOther changes\n-------------\n  * Update travis job to support multiple iOS versions\n  * Add test for preview effect with duration parameter\n  * Recover `Cloudinary.xcodeproj` file\n  * Fix `ImageView` size in preview widget `CollectionView`\n  * Improve network error handling\n  * Add `PNG` image upload unit tests\n\n3.1.0 / 2021-12-03\n==================\n\nNew functionality\n-----------------\n* Add support for `backgroundRemoval` upload parameter\n\nOther changes\n-------------\n  * Fix `Carthage`\n\n3.0.3 / 2021-11-14\n==================\n\n  * Fix error handling in `fetchImage`\n\n3.0.2 / 2021-11-02\n==================\n\n  * Improve error handling in `fetchImage`\n\n3.0.1 / 2021-08-31\n=============\n\n  * Fix deprecation warnings\n\n3.0.0 / 2021-04-26\n=============\n\nBreaking changes\n-----------------\n  * Bump minimum iOS target version to 9.0 (#334)\n\nNew functionality\n-----------------\n  * Add new url cache system (#331)\n  * Add operationQueue names (#333)\n  * Add support for video assets in upload widget (#322)\n\nOther changes\n-------------\n  * Fix image assets for tests in multiple OS versions (#329)\n  * Add missing imports for SPM (#326)\n\n2.10.1 / 2021-01-20\n==================\n\n  * Re-add `Cloudinary.xscheme` to fix carthage support (#324)\n\n2.10.0 / 2021-01-10\n==================\n\nNew functionality\n-----------------\n* Add Upload Widget (#320)\n* Add support for crop preprocess action (#263)\n* Add support for rotation preprocess action (#264)\n* Add support for enhanced quality analysis scores\n* Add support for user defined variables and conditional expressions (#238)\n* Support array of values for radius (#235)\n* Add `eval` parameter to the upload Params.\n* Add support for accessibility analysis (#260)\n* Add option to control url signature algorithm (#256)\n* Add support for custom pre-functions (#253)\n* Add support for Long signature in URLs (#250)\n* Add global timeout support(#251)\n* Add OCR support un transformations and Upload APIs.\n\nOther changes\n-------------\n* Add checks to validate responsive transformation.\n* Fix space encoding in a generated URL (#274)\n* Change local cache-keys encoding to `sha256`\n* Fix OCR parameter usage in `UploadRequestParamsTests` (#262)\n* Support urls with mime-type suffix in uploader.\n* Update SPM definitions file (#234)\n\n2.9.0 / 2020-04-16\n==================\n* Remove Alamofire dependency (#229)\n* Add Swift Package Manager support.\n* Add Carthage support.\n* Rearrange workspace (#226)\n* Add support for `assist_colorblind` effect. (#227)\n* Validate URL scheme (#224)\n\n\n2.9.0-beta.2 / 2020-04-05\n=========================\n\n  * Remove Alamofire dependency (#229)\n\n2.9.0-beta.1 / 2020-03-23\n=========================\n\n  * Add Swift Package Manager support.\n  * Add Carthage support.\n  * Rearrange workspace (#226)\n  * Add support for `assist_colorblind` effect. (#227)\n  * Validate URL scheme (#224)\n\n2.8.0 / 2019-11-11\n==================\n\n  * Add shared scheme (#220)\n  * Add support for artistic filters. (#214)\n  * Fix chunk upload to keep original file name. (#217)\n  * Fix face coordinates test. (#215)\n\n2.7.0 / 2019-04-07\n==================\n\nNew functionality\n-----------------\n  * Support swift 5, fix related warnings.\n  * Bump Alamofire version to 4.8.2\n  * Add support for fetch layer in transformations. (#197)\n  * Add support for `quality_analysis` parameter in upload. (#195)\n  * Add support for font antialiasing and hinting in text overlays. (#193)\n  * Add support for `streaming_profile` param in `CLDTransformation`. (#194)\n  * Support excluding the default version from the generated cloudinary-url. (#206)\n  * Add quality_override parameter to upload/explicit. (#199)\n  \nOther changes\n-------------\n  * Replace crypto kit files with `CommonCrypto` import.\n  * Fix memory cache limit not getting initially set in `CLDImageCache` (#201)\n  * Fix bas64 string validation in uploader. (#196)\n\n2.6.1 / 2019-01-30\n==================\n\n  * Fix project setup and tests for swift 4.2 (#191)\n\n2.6.0 / 2019-01-29\n==================\n\nNew functionality\n-----------------\n  * Add support for google storage (`gs://`) urls in uploader. (#184)\n  * Add support for `fps` parameter in Transformations. (#182)\n  * Add format field to responsive breakpoints in upload params (#152)\n  * Add `removeFromCache` to `CLDCloudinary`\n\nOther changes\n-------------\n  * Bump Alamofire version to 4.8.1\n  * Add device and os data to user agent. (#180)\n  * Remove duplicate Alamofire reference\n  \n2.5.0 / 2018-11-05\n==================\n\n  * Migrate to Swift 4.2\n  * Add support for custom transformation functions\n  * Fix duplicate upload callbacks when using preprocessing\n  * Bump Alamofire to version to 4.7.3\n  * Add String extensions for base64 encoding\n  * Add `@discardableResult` annotations for uploadLarge methods\n\n2.4.0 / 2018-06-26\n==================\n\nNew functionality\n-----------------\n  * Add support for `async` upload parameter\n  * Add support for eager transformation format\n  * Add support for automatic quality in transformations. (#150)\n  * Add cache max-memory config (#98)\n  * Add Keyframe interval transformation parameter (#90)\n\nOther changes\n-------------\n  * Refactor CLDBaseParam for compatibility with iOS 11.4\n  * Remove wrong project config (library search paths)\n  * Bump Alamofire version to 4.7.2\n  * Fix Alamofire submodule definition\n  * Fix signature parameter handling in Management Api. (#161)\n  * Fix `faceCenter` and `facesCenter` values in `CLDGravity` (#159)\n  * Fix calculation of UIImage memory cache cost\n\n2.3.0 / 2018-03-16\n==================\n\n  * Add access control parameter to upload (#142)\n\n2.2.2 / 2018-03-05\n==================\n\n  * Add baseline Objective-C test.\n  * Use `@objcMembers` where applies, for improved Objective-C compatibility.\n\n2.2.1 / 2018-02-14\n==================\n\n   * Fix objective-c compatibility issues with `CLDResponsiveParams` properties.\n\n2.2.0 / 2018-02-01\n==================\n\nNew functionality\n-----------------\n\n  * Add support for responsive image download\n  * Add `auto` to `CLDGravity`\n    \nOther changes\n-------------\n\n  * Fix synchronization issue when using `cldSetImage()` on `UIViews` within view collections.\n\n2.1.0 / 2018-01-04\n==================\n\nNew functionality\n-----------------\n\n  * Add image preprocessing and validations\n    * Resizing\n    * Format and quality settings\n    * Support for custom preprocessors and validators\n    \nOther changes\n-------------\n\n  * Remove custom operators\n  * Update Alamofire to version 4.6.0\n\n2.0.4 / 2017-12-20\n==================\n\n* Fix user-agent sdk version\n* Replace CommonCrypto wrapper with CryptoKit based code\n* Remove autotagging test (behaviour change)\n* Support Swift 4\n\n2.0.3 / 2017-11-23\n==================\n\nNew functionality\n-----------------\n  * Add support for chunked upload\n\nOther changes\n-------------\n\n  * Update Readme to point to HTTPS URLs of cloudinary.com\n  * Fix manual installation repository url.\n\n2.0.2 / 2017-06-08\n==================\n\nNew functionality\n-----------------\n\n  * Support SEO suffix for private images.\n\nOther changes\n-------------\n\n  * Escape `|` and `=` characters in context values.\n  * Double encode commas and slashes instead of using special UTF-8 values\n  * Generate CLDCrypto framework in every build. Fixes #80.\n  * Removing extra CLDCrypto path from podspec\n  * Update `README.md` Alamo version to 4.1.0\n  * Add 3 images in PhotoViewController to demonstrate transformations.\n  * Add progress indicator\n  * Updated the framework and project deployment target to 8.0, updated podspec deployment target to 8.0\n  * Fixed signed upload using CLDSignature - Added unit test to test a signed upload using CLDSignature\n\n2.0.1 / 2017-01-24\n==================\n\n  * Fix pod install issue. Fixes #57.\n  * Fix shellScript\n  * Fix URLs in tests\n  * Increment Alamofire to ~>4.1. Fixes #59.\n  * Update configuration\n\n2.0.1 / 2017-01-22\n==================\n\n  * Fix Framework path in podspec/xcconfig\n\n2.0.0 / 2017-01-18\n==================\n\n  * New Swift 3.0 code\n"
  },
  {
    "path": "Cloudinary/Assets/.gitkeep",
    "content": ""
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNConvertible.swift",
    "content": "//\n//  CLDNConvertible.swift\n//\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\nimport Foundation\n\n/// Types adopting the `CLDNURLConvertible` protocol can be used to construct URLs, which are then used to construct\n/// URL requests.\ninternal protocol CLDNURLConvertible {\n    /// Returns a URL that conforms to RFC 2396 or throws an `Error`.\n    ///\n    /// - throws: An `Error` if the type cannot be converted to a `URL`.\n    ///\n    /// - returns: A URL or throws an `Error`.\n    func CLDN_AsURL() throws -> URL\n}\n\nextension String: CLDNURLConvertible {\n    /// Returns a URL if `self` represents a valid URL string that conforms to RFC 2396 or throws an `CLDNError`.\n    ///\n    /// - throws: An `CLDNError.invalidURL` if `self` is not a valid URL string.\n    ///\n    /// - returns: A URL or throws an `CLDNError`.\n    internal func CLDN_AsURL() throws -> URL {\n        guard let url = URL(string: self) else { throw CLDNError.invalidURL(url: self) }\n        return url\n    }\n}\n\nextension URL: CLDNURLConvertible {\n    /// Returns self.\n    internal func CLDN_AsURL() throws -> URL { return self }\n}\n\nextension URLComponents: CLDNURLConvertible {\n    /// Returns a URL if `url` is not nil, otherwise throws an `Error`.\n    ///\n    /// - throws: An `CLDNError.invalidURL` if `url` is `nil`.\n    ///\n    /// - returns: A URL or throws an `CLDNError`.\n    internal func CLDN_AsURL() throws -> URL {\n        guard let url = url else { throw CLDNError.invalidURL(url: self) }\n        return url\n    }\n}\n\n// MARK: -\n\n/// Types adopting the `CLDNURLRequestConvertible` protocol can be used to construct URL requests.\ninternal protocol CLDNURLRequestConvertible {\n    /// Returns a URL request or throws if an `Error` was encountered.\n    ///\n    /// - throws: An `Error` if the underlying `URLRequest` is `nil`.\n    ///\n    /// - returns: A URL request.\n    func CLDN_AsURLRequest() throws -> URLRequest\n}\n\nextension CLDNURLRequestConvertible {\n    /// The URL request.\n    internal var urlRequest: URLRequest? { return try? CLDN_AsURLRequest() }\n}\n\nextension URLRequest: CLDNURLRequestConvertible {\n    /// Returns a URL request or throws if an `Error` was encountered.\n    internal func CLDN_AsURLRequest() throws -> URLRequest { return self }\n}\n\n// MARK: -\n\nextension URLRequest {\n    /// Creates an instance with the specified `method`, `urlString` and `headers`.\n    ///\n    /// - parameter url:     The URL.\n    /// - parameter method:  The HTTP method.\n    /// - parameter headers: The HTTP headers. `nil` by default.\n    ///\n    /// - returns: The new `URLRequest` instance.\n    internal init(url: CLDNURLConvertible, method: CLDNHTTPMethod, headers: CLDNHTTPHeaders? = nil) throws {\n        let url = try url.CLDN_AsURL()\n\n        self.init(url: url)\n\n        httpMethod = method.rawValue\n\n        if let headers = headers {\n            for (headerField, headerValue) in headers {\n                setValue(headerValue, forHTTPHeaderField: headerField)\n            }\n        }\n    }\n\n    func adapt(using adapter: CLDNRequestAdapter?) throws -> URLRequest {\n        guard let adapter = adapter else { return self }\n        return try adapter.CLDN_Adapt(self)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNError.swift",
    "content": "//\n//  CLDNError.swift\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\nimport Foundation\n\n/// `CLDNError` is the error type returned by Cloudinary. It encompasses a few different types of errors, each with\n/// their own associated reasons.\n///\n/// - invalidURL:                  Returned when a `URLConvertible` type fails to create a valid `URL`.\n/// - parameterEncodingFailed:     Returned when a parameter encoding object throws an error during the encoding process.\n/// - multipartEncodingFailed:     Returned when some step in the multipart encoding process fails.\n/// - responseValidationFailed:    Returned when a `validate()` call fails.\n/// - responseSerializationFailed: Returned when a response serializer encounters an error in the serialization process.\ninternal enum CLDNError: Error {\n    /// The underlying reason the parameter encoding error occurred.\n    ///\n    /// - missingURL:                 The URL request did not have a URL to encode.\n    /// - jsonEncodingFailed:         JSON serialization failed with an underlying system error during the\n    ///                               encoding process.\n    /// - propertyListEncodingFailed: Property list serialization failed with an underlying system error during\n    ///                               encoding process.\n    internal enum ParameterEncodingFailureReason {\n        case missingURL\n        case jsonEncodingFailed(error: Error)\n        case propertyListEncodingFailed(error: Error)\n    }\n\n    /// The underlying reason the multipart encoding error occurred.\n    ///\n    /// - bodyPartURLInvalid:                   The `fileURL` provided for reading an encodable body part isn't a\n    ///                                         file URL.\n    /// - bodyPartFilenameInvalid:              The filename of the `fileURL` provided has either an empty\n    ///                                         `lastPathComponent` or `pathExtension.\n    /// - bodyPartFileNotReachable:             The file at the `fileURL` provided was not reachable.\n    /// - bodyPartFileNotReachableWithError:    Attempting to check the reachability of the `fileURL` provided threw\n    ///                                         an error.\n    /// - bodyPartFileIsDirectory:              The file at the `fileURL` provided is actually a directory.\n    /// - bodyPartFileSizeNotAvailable:         The size of the file at the `fileURL` provided was not returned by\n    ///                                         the system.\n    /// - bodyPartFileSizeQueryFailedWithError: The attempt to find the size of the file at the `fileURL` provided\n    ///                                         threw an error.\n    /// - bodyPartInputStreamCreationFailed:    An `InputStream` could not be created for the provided `fileURL`.\n    /// - outputStreamCreationFailed:           An `OutputStream` could not be created when attempting to write the\n    ///                                         encoded data to disk.\n    /// - outputStreamFileAlreadyExists:        The encoded body data could not be writtent disk because a file\n    ///                                         already exists at the provided `fileURL`.\n    /// - outputStreamURLInvalid:               The `fileURL` provided for writing the encoded body data to disk is\n    ///                                         not a file URL.\n    /// - outputStreamWriteFailed:              The attempt to write the encoded body data to disk failed with an\n    ///                                         underlying error.\n    /// - inputStreamReadFailed:                The attempt to read an encoded body part `InputStream` failed with\n    ///                                         underlying system error.\n    internal enum MultipartEncodingFailureReason {\n        case bodyPartURLInvalid(url: URL)\n        case bodyPartFilenameInvalid(in: URL)\n        case bodyPartFileNotReachable(at: URL)\n        case bodyPartFileNotReachableWithError(atURL: URL, error: Error)\n        case bodyPartFileIsDirectory(at: URL)\n        case bodyPartFileSizeNotAvailable(at: URL)\n        case bodyPartFileSizeQueryFailedWithError(forURL: URL, error: Error)\n        case bodyPartInputStreamCreationFailed(for: URL)\n\n        case outputStreamCreationFailed(for: URL)\n        case outputStreamFileAlreadyExists(at: URL)\n        case outputStreamURLInvalid(url: URL)\n        case outputStreamWriteFailed(error: Error)\n\n        case inputStreamReadFailed(error: Error)\n    }\n\n    /// The underlying reason the response validation error occurred.\n    ///\n    /// - dataFileNil:             The data file containing the server response did not exist.\n    /// - dataFileReadFailed:      The data file containing the server response could not be read.\n    /// - missingContentType:      The response did not contain a `Content-Type` and the `acceptableContentTypes`\n    ///                            provided did not contain wildcard type.\n    /// - unacceptableContentType: The response `Content-Type` did not match any type in the provided\n    ///                            `acceptableContentTypes`.\n    /// - unacceptableStatusCode:  The response status code was not acceptable.\n    internal enum ResponseValidationFailureReason {\n        case dataFileNil\n        case dataFileReadFailed(at: URL)\n        case missingContentType(acceptableContentTypes: [String])\n        case unacceptableContentType(acceptableContentTypes: [String], responseContentType: String)\n        case unacceptableStatusCode(code: Int)\n    }\n\n    /// The underlying reason the response serialization error occurred.\n    ///\n    /// - inputDataNil:                    The server response contained no data.\n    /// - inputDataNilOrZeroLength:        The server response contained no data or the data was zero length.\n    /// - inputFileNil:                    The file containing the server response did not exist.\n    /// - inputFileReadFailed:             The file containing the server response could not be read.\n    /// - stringSerializationFailed:       String serialization failed using the provided `String.Encoding`.\n    /// - jsonSerializationFailed:         JSON serialization failed with an underlying system error.\n    /// - propertyListSerializationFailed: Property list serialization failed with an underlying system error.\n    internal enum ResponseSerializationFailureReason {\n        case inputDataNil\n        case inputDataNilOrZeroLength\n        case inputFileNil\n        case inputFileReadFailed(at: URL)\n        case stringSerializationFailed(encoding: String.Encoding)\n        case jsonSerializationFailed(error: Error)\n        case propertyListSerializationFailed(error: Error)\n    }\n\n    case invalidURL(url: CLDNURLConvertible)\n    case parameterEncodingFailed(reason: ParameterEncodingFailureReason)\n    case multipartEncodingFailed(reason: MultipartEncodingFailureReason)\n    case responseValidationFailed(reason: ResponseValidationFailureReason)\n    case responseSerializationFailed(reason: ResponseSerializationFailureReason)\n}\n\n// MARK: - Adapt Error\n\nstruct AdaptError: Error {\n    let error: Error\n}\n\nextension Error {\n    var underlyingAdaptError: Error? { return (self as? AdaptError)?.error }\n}\n\n// MARK: - Error Booleans\n\nextension CLDNError {\n    /// Returns whether the CLDNError is an invalid URL error.\n    internal var isInvalidURLError: Bool {\n        if case .invalidURL = self { return true }\n        return false\n    }\n\n    /// Returns whether the CLDNError is a parameter encoding error. When `true`, the `underlyingError` property will\n    /// contain the associated value.\n    internal var isParameterEncodingError: Bool {\n        if case .parameterEncodingFailed = self { return true }\n        return false\n    }\n\n    /// Returns whether the CLDNError is a multipart encoding error. When `true`, the `url` and `underlyingError` properties\n    /// will contain the associated values.\n    internal var isMultipartEncodingError: Bool {\n        if case .multipartEncodingFailed = self { return true }\n        return false\n    }\n\n    /// Returns whether the `CLDNError` is a response validation error. When `true`, the `acceptableContentTypes`,\n    /// `responseContentType`, and `responseCode` properties will contain the associated values.\n    internal var isResponseValidationError: Bool {\n        if case .responseValidationFailed = self { return true }\n        return false\n    }\n\n    /// Returns whether the `CLDNError` is a response serialization error. When `true`, the `failedStringEncoding` and\n    /// `underlyingError` properties will contain the associated values.\n    internal var isResponseSerializationError: Bool {\n        if case .responseSerializationFailed = self { return true }\n        return false\n    }\n}\n\n// MARK: - Convenience Properties\n\nextension CLDNError {\n    /// The `URLConvertible` associated with the error.\n    var urlConvertible: CLDNURLConvertible? {\n        switch self {\n        case .invalidURL(let url):\n            return url\n        default:\n            return nil\n        }\n    }\n\n    /// The `URL` associated with the error.\n    internal var url: URL? {\n        switch self {\n        case .multipartEncodingFailed(let reason):\n            return reason.url\n        default:\n            return nil\n        }\n    }\n\n    /// The `Error` returned by a system framework associated with a `.parameterEncodingFailed`,\n    /// `.multipartEncodingFailed` or `.responseSerializationFailed` error.\n    internal var underlyingError: Error? {\n        switch self {\n        case .parameterEncodingFailed(let reason):\n            return reason.underlyingError\n        case .multipartEncodingFailed(let reason):\n            return reason.underlyingError\n        case .responseSerializationFailed(let reason):\n            return reason.underlyingError\n        default:\n            return nil\n        }\n    }\n\n    /// The acceptable `Content-Type`s of a `.responseValidationFailed` error.\n    internal var acceptableContentTypes: [String]? {\n        switch self {\n        case .responseValidationFailed(let reason):\n            return reason.acceptableContentTypes\n        default:\n            return nil\n        }\n    }\n\n    /// The response `Content-Type` of a `.responseValidationFailed` error.\n    internal var responseContentType: String? {\n        switch self {\n        case .responseValidationFailed(let reason):\n            return reason.responseContentType\n        default:\n            return nil\n        }\n    }\n\n    /// The response code of a `.responseValidationFailed` error.\n    internal var responseCode: Int? {\n        switch self {\n        case .responseValidationFailed(let reason):\n            return reason.responseCode\n        default:\n            return nil\n        }\n    }\n\n    /// The `String.Encoding` associated with a failed `.stringResponse()` call.\n    internal var failedStringEncoding: String.Encoding? {\n        switch self {\n        case .responseSerializationFailed(let reason):\n            return reason.failedStringEncoding\n        default:\n            return nil\n        }\n    }\n}\n\nextension CLDNError.ParameterEncodingFailureReason {\n    var underlyingError: Error? {\n        switch self {\n        case .jsonEncodingFailed(let error), .propertyListEncodingFailed(let error):\n            return error\n        default:\n            return nil\n        }\n    }\n}\n\nextension CLDNError.MultipartEncodingFailureReason {\n    var url: URL? {\n        switch self {\n        case .bodyPartURLInvalid(let url), .bodyPartFilenameInvalid(let url), .bodyPartFileNotReachable(let url),\n             .bodyPartFileIsDirectory(let url), .bodyPartFileSizeNotAvailable(let url),\n             .bodyPartInputStreamCreationFailed(let url), .outputStreamCreationFailed(let url),\n             .outputStreamFileAlreadyExists(let url), .outputStreamURLInvalid(let url),\n             .bodyPartFileNotReachableWithError(let url, _), .bodyPartFileSizeQueryFailedWithError(let url, _):\n            return url\n        default:\n            return nil\n        }\n    }\n\n    var underlyingError: Error? {\n        switch self {\n        case .bodyPartFileNotReachableWithError(_, let error), .bodyPartFileSizeQueryFailedWithError(_, let error),\n             .outputStreamWriteFailed(let error), .inputStreamReadFailed(let error):\n            return error\n        default:\n            return nil\n        }\n    }\n}\n\nextension CLDNError.ResponseValidationFailureReason {\n    var acceptableContentTypes: [String]? {\n        switch self {\n        case .missingContentType(let types), .unacceptableContentType(let types, _):\n            return types\n        default:\n            return nil\n        }\n    }\n\n    var responseContentType: String? {\n        switch self {\n        case .unacceptableContentType(_, let responseType):\n            return responseType\n        default:\n            return nil\n        }\n    }\n\n    var responseCode: Int? {\n        switch self {\n        case .unacceptableStatusCode(let code):\n            return code\n        default:\n            return nil\n        }\n    }\n}\n\nextension CLDNError.ResponseSerializationFailureReason {\n    var failedStringEncoding: String.Encoding? {\n        switch self {\n        case .stringSerializationFailed(let encoding):\n            return encoding\n        default:\n            return nil\n        }\n    }\n\n    var underlyingError: Error? {\n        switch self {\n        case .jsonSerializationFailed(let error), .propertyListSerializationFailed(let error):\n            return error\n        default:\n            return nil\n        }\n    }\n}\n\n// MARK: - Error Descriptions\n\nextension CLDNError: LocalizedError {\n    internal var errorDescription: String? {\n        switch self {\n        case .invalidURL(let url):\n            return \"URL is not valid: \\(url)\"\n        case .parameterEncodingFailed(let reason):\n            return reason.localizedDescription\n        case .multipartEncodingFailed(let reason):\n            return reason.localizedDescription\n        case .responseValidationFailed(let reason):\n            return reason.localizedDescription\n        case .responseSerializationFailed(let reason):\n            return reason.localizedDescription\n        }\n    }\n}\n\nextension CLDNError.ParameterEncodingFailureReason {\n    var localizedDescription: String {\n        switch self {\n        case .missingURL:\n            return \"URL request to encode was missing a URL\"\n        case .jsonEncodingFailed(let error):\n            return \"JSON could not be encoded because of error:\\n\\(error.localizedDescription)\"\n        case .propertyListEncodingFailed(let error):\n            return \"PropertyList could not be encoded because of error:\\n\\(error.localizedDescription)\"\n        }\n    }\n}\n\nextension CLDNError.MultipartEncodingFailureReason {\n    var localizedDescription: String {\n        switch self {\n        case .bodyPartURLInvalid(let url):\n            return \"The URL provided is not a file URL: \\(url)\"\n        case .bodyPartFilenameInvalid(let url):\n            return \"The URL provided does not have a valid filename: \\(url)\"\n        case .bodyPartFileNotReachable(let url):\n            return \"The URL provided is not reachable: \\(url)\"\n        case .bodyPartFileNotReachableWithError(let url, let error):\n            return (\n                \"The system returned an error while checking the provided URL for \" +\n                \"reachability.\\nURL: \\(url)\\nError: \\(error)\"\n            )\n        case .bodyPartFileIsDirectory(let url):\n            return \"The URL provided is a directory: \\(url)\"\n        case .bodyPartFileSizeNotAvailable(let url):\n            return \"Could not fetch the file size from the provided URL: \\(url)\"\n        case .bodyPartFileSizeQueryFailedWithError(let url, let error):\n            return (\n                \"The system returned an error while attempting to fetch the file size from the \" +\n                \"provided URL.\\nURL: \\(url)\\nError: \\(error)\"\n            )\n        case .bodyPartInputStreamCreationFailed(let url):\n            return \"Failed to create an InputStream for the provided URL: \\(url)\"\n        case .outputStreamCreationFailed(let url):\n            return \"Failed to create an OutputStream for URL: \\(url)\"\n        case .outputStreamFileAlreadyExists(let url):\n            return \"A file already exists at the provided URL: \\(url)\"\n        case .outputStreamURLInvalid(let url):\n            return \"The provided OutputStream URL is invalid: \\(url)\"\n        case .outputStreamWriteFailed(let error):\n            return \"OutputStream write failed with error: \\(error)\"\n        case .inputStreamReadFailed(let error):\n            return \"InputStream read failed with error: \\(error)\"\n        }\n    }\n}\n\nextension CLDNError.ResponseSerializationFailureReason {\n    var localizedDescription: String {\n        switch self {\n        case .inputDataNil:\n            return \"Response could not be serialized, input data was nil.\"\n        case .inputDataNilOrZeroLength:\n            return \"Response could not be serialized, input data was nil or zero length.\"\n        case .inputFileNil:\n            return \"Response could not be serialized, input file was nil.\"\n        case .inputFileReadFailed(let url):\n            return \"Response could not be serialized, input file could not be read: \\(url).\"\n        case .stringSerializationFailed(let encoding):\n            return \"String could not be serialized with encoding: \\(encoding).\"\n        case .jsonSerializationFailed(let error):\n            return \"JSON could not be serialized because of error:\\n\\(error.localizedDescription)\"\n        case .propertyListSerializationFailed(let error):\n            return \"PropertyList could not be serialized because of error:\\n\\(error.localizedDescription)\"\n        }\n    }\n}\n\nextension CLDNError.ResponseValidationFailureReason {\n    var localizedDescription: String {\n        switch self {\n        case .dataFileNil:\n            return \"Response could not be validated, data file was nil.\"\n        case .dataFileReadFailed(let url):\n            return \"Response could not be validated, data file could not be read: \\(url).\"\n        case .missingContentType(let types):\n            return (\n                \"Response Content-Type was missing and acceptable content types \" +\n                \"(\\(types.joined(separator: \",\"))) do not match \\\"*/*\\\".\"\n            )\n        case .unacceptableContentType(let acceptableTypes, let responseType):\n            return (\n                \"Response Content-Type \\\"\\(responseType)\\\" does not match any acceptable types: \" +\n                \"\\(acceptableTypes.joined(separator: \",\")).\"\n            )\n        case .unacceptableStatusCode(let code):\n            return \"Response status code was unacceptable: \\(code).\"\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNMultipartFormData.swift",
    "content": "//\n//  CLDNMultipartFormData.swift\n//\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\nimport Foundation\n\n#if os(iOS) || os(watchOS) || os(tvOS)\nimport MobileCoreServices\n#elseif os(macOS)\nimport CoreServices\n#endif\n\n/// Constructs `multipart/form-data` for uploads within an HTTP or HTTPS body. There are currently two ways to encode\n/// multipart form data. The first way is to encode the data directly in memory. This is very efficient, but can lead\n/// to memory issues if the dataset is too large. The second way is designed for larger datasets and will write all the\n/// data to a single file on disk with all the proper boundary segmentation. The second approach MUST be used for\n/// larger datasets such as video content, otherwise your app may run out of memory when trying to encode the dataset.\n///\n/// For more information on `multipart/form-data` in general, please refer to the RFC-2388 and RFC-2045 specs as well\n/// and the w3 form documentation.\n///\n/// - https://www.ietf.org/rfc/rfc2388.txt\n/// - https://www.ietf.org/rfc/rfc2045.txt\n/// - https://www.w3.org/TR/html401/interact/forms.html#h-17.13\ninternal class CLDNMultipartFormData {\n\n    // MARK: - Helper Types\n\n    struct EncodingCharacters {\n        static let crlf = \"\\r\\n\"\n    }\n\n    struct BoundaryGenerator {\n        enum BoundaryType {\n            case initial, encapsulated, final\n        }\n\n        static func randomBoundary() -> String {\n            return String(format: \"Cloudinary.boundary.%08x%08x\", arc4random(), arc4random())\n        }\n\n        static func boundaryData(forBoundaryType boundaryType: BoundaryType, boundary: String) -> Data {\n            let boundaryText: String\n\n            switch boundaryType {\n            case .initial:\n                boundaryText = \"--\\(boundary)\\(EncodingCharacters.crlf)\"\n            case .encapsulated:\n                boundaryText = \"\\(EncodingCharacters.crlf)--\\(boundary)\\(EncodingCharacters.crlf)\"\n            case .final:\n                boundaryText = \"\\(EncodingCharacters.crlf)--\\(boundary)--\\(EncodingCharacters.crlf)\"\n            }\n\n            return boundaryText.data(using: String.Encoding.utf8, allowLossyConversion: false)!\n        }\n    }\n\n    class BodyPart {\n        let headers: CLDNHTTPHeaders\n        let bodyStream: InputStream\n        let bodyContentLength: UInt64\n        var hasInitialBoundary = false\n        var hasFinalBoundary = false\n\n        init(headers: CLDNHTTPHeaders, bodyStream: InputStream, bodyContentLength: UInt64) {\n            self.headers = headers\n            self.bodyStream = bodyStream\n            self.bodyContentLength = bodyContentLength\n        }\n    }\n\n    // MARK: - Properties\n\n    /// The `Content-Type` header value containing the boundary used to generate the `multipart/form-data`.\n    internal lazy var contentType: String = \"multipart/form-data; boundary=\\(self.boundary)\"\n\n    /// The content length of all body parts used to generate the `multipart/form-data` not including the boundaries.\n    internal var contentLength: UInt64 { return bodyParts.reduce(0) { $0 + $1.bodyContentLength } }\n\n    /// The boundary used to separate the body parts in the encoded form data.\n    internal var boundary: String\n\n    private var bodyParts: [BodyPart]\n    private var bodyPartError: CLDNError?\n    private let streamBufferSize: Int\n\n    // MARK: - Lifecycle\n\n    /// Creates a multipart form data object.\n    ///\n    /// - returns: The multipart form data object.\n    internal init() {\n        self.boundary = BoundaryGenerator.randomBoundary()\n        self.bodyParts = []\n\n        ///\n        /// The optimal read/write buffer size in bytes for input and output streams is 1024 (1KB). For more\n        /// information, please refer to the following article:\n        ///   - https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html\n        ///\n\n        self.streamBufferSize = 1024\n    }\n\n    // MARK: - Body Parts\n\n    /// Creates a body part from the data and appends it to the multipart form data object.\n    ///\n    /// The body part data will be encoded using the following format:\n    ///\n    /// - `Content-Disposition: form-data; name=#{name}` (HTTP Header)\n    /// - Encoded data\n    /// - Multipart form boundary\n    ///\n    /// - parameter data: The data to encode into the multipart form data.\n    /// - parameter name: The name to associate with the data in the `Content-Disposition` HTTP header.\n    internal func append(_ data: Data, withName name: String) {\n        let headers = contentHeaders(withName: name)\n        let stream = InputStream(data: data)\n        let length = UInt64(data.count)\n\n        append(stream, withLength: length, headers: headers)\n    }\n\n    /// Creates a body part from the data and appends it to the multipart form data object.\n    ///\n    /// The body part data will be encoded using the following format:\n    ///\n    /// - `Content-Disposition: form-data; name=#{name}` (HTTP Header)\n    /// - `Content-Type: #{generated mimeType}` (HTTP Header)\n    /// - Encoded data\n    /// - Multipart form boundary\n    ///\n    /// - parameter data:     The data to encode into the multipart form data.\n    /// - parameter name:     The name to associate with the data in the `Content-Disposition` HTTP header.\n    /// - parameter mimeType: The MIME type to associate with the data content type in the `Content-Type` HTTP header.\n    internal func append(_ data: Data, withName name: String, mimeType: String) {\n        let headers = contentHeaders(withName: name, mimeType: mimeType)\n        let stream = InputStream(data: data)\n        let length = UInt64(data.count)\n\n        append(stream, withLength: length, headers: headers)\n    }\n\n    /// Creates a body part from the data and appends it to the multipart form data object.\n    ///\n    /// The body part data will be encoded using the following format:\n    ///\n    /// - `Content-Disposition: form-data; name=#{name}; filename=#{filename}` (HTTP Header)\n    /// - `Content-Type: #{mimeType}` (HTTP Header)\n    /// - Encoded file data\n    /// - Multipart form boundary\n    ///\n    /// - parameter data:     The data to encode into the multipart form data.\n    /// - parameter name:     The name to associate with the data in the `Content-Disposition` HTTP header.\n    /// - parameter fileName: The filename to associate with the data in the `Content-Disposition` HTTP header.\n    /// - parameter mimeType: The MIME type to associate with the data in the `Content-Type` HTTP header.\n    internal func append(_ data: Data, withName name: String, fileName: String, mimeType: String) {\n        let headers = contentHeaders(withName: name, fileName: fileName, mimeType: mimeType)\n        let stream = InputStream(data: data)\n        let length = UInt64(data.count)\n\n        append(stream, withLength: length, headers: headers)\n    }\n\n    /// Creates a body part from the file and appends it to the multipart form data object.\n    ///\n    /// The body part data will be encoded using the following format:\n    ///\n    /// - `Content-Disposition: form-data; name=#{name}; filename=#{generated filename}` (HTTP Header)\n    /// - `Content-Type: #{generated mimeType}` (HTTP Header)\n    /// - Encoded file data\n    /// - Multipart form boundary\n    ///\n    /// The filename in the `Content-Disposition` HTTP header is generated from the last path component of the\n    /// `fileURL`. The `Content-Type` HTTP header MIME type is generated by mapping the `fileURL` extension to the\n    /// system associated MIME type.\n    ///\n    /// - parameter fileURL: The URL of the file whose content will be encoded into the multipart form data.\n    /// - parameter name:    The name to associate with the file content in the `Content-Disposition` HTTP header.\n    internal func append(_ fileURL: URL, withName name: String) {\n        let fileName = fileURL.lastPathComponent\n        let pathExtension = fileURL.pathExtension\n\n        if !fileName.isEmpty && !pathExtension.isEmpty {\n            let mime = mimeType(forPathExtension: pathExtension)\n            append(fileURL, withName: name, fileName: fileName, mimeType: mime)\n        } else {\n            setBodyPartError(withReason: .bodyPartFilenameInvalid(in: fileURL))\n        }\n    }\n\n    /// Creates a body part from the file and appends it to the multipart form data object.\n    ///\n    /// The body part data will be encoded using the following format:\n    ///\n    /// - Content-Disposition: form-data; name=#{name}; filename=#{filename} (HTTP Header)\n    /// - Content-Type: #{mimeType} (HTTP Header)\n    /// - Encoded file data\n    /// - Multipart form boundary\n    ///\n    /// - parameter fileURL:  The URL of the file whose content will be encoded into the multipart form data.\n    /// - parameter name:     The name to associate with the file content in the `Content-Disposition` HTTP header.\n    /// - parameter fileName: The filename to associate with the file content in the `Content-Disposition` HTTP header.\n    /// - parameter mimeType: The MIME type to associate with the file content in the `Content-Type` HTTP header.\n    internal func append(_ fileURL: URL, withName name: String, fileName: String, mimeType: String) {\n        let headers = contentHeaders(withName: name, fileName: fileName, mimeType: mimeType)\n\n        //============================================================\n        //                 Check 1 - is file URL?\n        //============================================================\n\n        guard fileURL.isFileURL else {\n            setBodyPartError(withReason: .bodyPartURLInvalid(url: fileURL))\n            return\n        }\n\n        //============================================================\n        //              Check 2 - is file URL reachable?\n        //============================================================\n\n        do {\n            let isReachable = try fileURL.checkPromisedItemIsReachable()\n            guard isReachable else {\n                setBodyPartError(withReason: .bodyPartFileNotReachable(at: fileURL))\n                return\n            }\n        } catch {\n            setBodyPartError(withReason: .bodyPartFileNotReachableWithError(atURL: fileURL, error: error))\n            return\n        }\n\n        //============================================================\n        //            Check 3 - is file URL a directory?\n        //============================================================\n\n        var isDirectory: ObjCBool = false\n        let path = fileURL.path\n\n        guard FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) && !isDirectory.boolValue else {\n            setBodyPartError(withReason: .bodyPartFileIsDirectory(at: fileURL))\n            return\n        }\n\n        //============================================================\n        //          Check 4 - can the file size be extracted?\n        //============================================================\n\n        let bodyContentLength: UInt64\n\n        do {\n            guard let fileSize = try FileManager.default.attributesOfItem(atPath: path)[.size] as? NSNumber else {\n                setBodyPartError(withReason: .bodyPartFileSizeNotAvailable(at: fileURL))\n                return\n            }\n\n            bodyContentLength = fileSize.uint64Value\n        }\n        catch {\n            setBodyPartError(withReason: .bodyPartFileSizeQueryFailedWithError(forURL: fileURL, error: error))\n            return\n        }\n\n        //============================================================\n        //       Check 5 - can a stream be created from file URL?\n        //============================================================\n\n        guard let stream = InputStream(url: fileURL) else {\n            setBodyPartError(withReason: .bodyPartInputStreamCreationFailed(for: fileURL))\n            return\n        }\n\n        append(stream, withLength: bodyContentLength, headers: headers)\n    }\n\n    /// Creates a body part from the stream and appends it to the multipart form data object.\n    ///\n    /// The body part data will be encoded using the following format:\n    ///\n    /// - `Content-Disposition: form-data; name=#{name}; filename=#{filename}` (HTTP Header)\n    /// - `Content-Type: #{mimeType}` (HTTP Header)\n    /// - Encoded stream data\n    /// - Multipart form boundary\n    ///\n    /// - parameter stream:   The input stream to encode in the multipart form data.\n    /// - parameter length:   The content length of the stream.\n    /// - parameter name:     The name to associate with the stream content in the `Content-Disposition` HTTP header.\n    /// - parameter fileName: The filename to associate with the stream content in the `Content-Disposition` HTTP header.\n    /// - parameter mimeType: The MIME type to associate with the stream content in the `Content-Type` HTTP header.\n    internal func append(\n        _ stream: InputStream,\n        withLength length: UInt64,\n        name: String,\n        fileName: String,\n        mimeType: String)\n    {\n        let headers = contentHeaders(withName: name, fileName: fileName, mimeType: mimeType)\n        append(stream, withLength: length, headers: headers)\n    }\n\n    /// Creates a body part with the headers, stream and length and appends it to the multipart form data object.\n    ///\n    /// The body part data will be encoded using the following format:\n    ///\n    /// - HTTP headers\n    /// - Encoded stream data\n    /// - Multipart form boundary\n    ///\n    /// - parameter stream:  The input stream to encode in the multipart form data.\n    /// - parameter length:  The content length of the stream.\n    /// - parameter headers: The HTTP headers for the body part.\n    internal func append(_ stream: InputStream, withLength length: UInt64, headers: CLDNHTTPHeaders) {\n        let bodyPart = BodyPart(headers: headers, bodyStream: stream, bodyContentLength: length)\n        bodyParts.append(bodyPart)\n    }\n\n    // MARK: - Data Encoding\n\n    /// Encodes all the appended body parts into a single `Data` value.\n    ///\n    /// It is important to note that this method will load all the appended body parts into memory all at the same\n    /// time. This method should only be used when the encoded data will have a small memory footprint. For large data\n    /// cases, please use the `writeEncodedDataToDisk(fileURL:completionHandler:)` method.\n    ///\n    /// - throws: An `CLDNError` if encoding encounters an error.\n    ///\n    /// - returns: The encoded `Data` if encoding is successful.\n    internal func encode() throws -> Data {\n        if let bodyPartError = bodyPartError {\n            throw bodyPartError\n        }\n\n        var encoded = Data()\n\n        bodyParts.first?.hasInitialBoundary = true\n        bodyParts.last?.hasFinalBoundary = true\n\n        for bodyPart in bodyParts {\n            let encodedData = try encode(bodyPart)\n            encoded.append(encodedData)\n        }\n\n        return encoded\n    }\n\n    /// Writes the appended body parts into the given file URL.\n    ///\n    /// This process is facilitated by reading and writing with input and output streams, respectively. Thus,\n    /// this approach is very memory efficient and should be used for large body part data.\n    ///\n    /// - parameter fileURL: The file URL to write the multipart form data into.\n    ///\n    /// - throws: An `CLDNError` if encoding encounters an error.\n    internal func writeEncodedData(to fileURL: URL) throws {\n        if let bodyPartError = bodyPartError {\n            throw bodyPartError\n        }\n\n        if FileManager.default.fileExists(atPath: fileURL.path) {\n            throw CLDNError.multipartEncodingFailed(reason: .outputStreamFileAlreadyExists(at: fileURL))\n        } else if !fileURL.isFileURL {\n            throw CLDNError.multipartEncodingFailed(reason: .outputStreamURLInvalid(url: fileURL))\n        }\n\n        guard let outputStream = OutputStream(url: fileURL, append: false) else {\n            throw CLDNError.multipartEncodingFailed(reason: .outputStreamCreationFailed(for: fileURL))\n        }\n\n        outputStream.open()\n        defer { outputStream.close() }\n\n        self.bodyParts.first?.hasInitialBoundary = true\n        self.bodyParts.last?.hasFinalBoundary = true\n\n        for bodyPart in self.bodyParts {\n            try write(bodyPart, to: outputStream)\n        }\n    }\n\n    // MARK: - Private - Body Part Encoding\n\n    private func encode(_ bodyPart: BodyPart) throws -> Data {\n        var encoded = Data()\n\n        let initialData = bodyPart.hasInitialBoundary ? initialBoundaryData() : encapsulatedBoundaryData()\n        encoded.append(initialData)\n\n        let headerData = encodeHeaders(for: bodyPart)\n        encoded.append(headerData)\n\n        let bodyStreamData = try encodeBodyStream(for: bodyPart)\n        encoded.append(bodyStreamData)\n\n        if bodyPart.hasFinalBoundary {\n            encoded.append(finalBoundaryData())\n        }\n\n        return encoded\n    }\n\n    private func encodeHeaders(for bodyPart: BodyPart) -> Data {\n        var headerText = \"\"\n\n        for (key, value) in bodyPart.headers {\n            headerText += \"\\(key): \\(value)\\(EncodingCharacters.crlf)\"\n        }\n        headerText += EncodingCharacters.crlf\n\n        return headerText.data(using: String.Encoding.utf8, allowLossyConversion: false)!\n    }\n\n    private func encodeBodyStream(for bodyPart: BodyPart) throws -> Data {\n        let inputStream = bodyPart.bodyStream\n        inputStream.open()\n        defer { inputStream.close() }\n\n        var encoded = Data()\n\n        while inputStream.hasBytesAvailable {\n            var buffer = [UInt8](repeating: 0, count: streamBufferSize)\n            let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize)\n\n            if let error = inputStream.streamError {\n                throw CLDNError.multipartEncodingFailed(reason: .inputStreamReadFailed(error: error))\n            }\n\n            if bytesRead > 0 {\n                encoded.append(buffer, count: bytesRead)\n            } else {\n                break\n            }\n        }\n\n        return encoded\n    }\n\n    // MARK: - Private - Writing Body Part to Output Stream\n\n    private func write(_ bodyPart: BodyPart, to outputStream: OutputStream) throws {\n        try writeInitialBoundaryData(for: bodyPart, to: outputStream)\n        try writeHeaderData(for: bodyPart, to: outputStream)\n        try writeBodyStream(for: bodyPart, to: outputStream)\n        try writeFinalBoundaryData(for: bodyPart, to: outputStream)\n    }\n\n    private func writeInitialBoundaryData(for bodyPart: BodyPart, to outputStream: OutputStream) throws {\n        let initialData = bodyPart.hasInitialBoundary ? initialBoundaryData() : encapsulatedBoundaryData()\n        return try write(initialData, to: outputStream)\n    }\n\n    private func writeHeaderData(for bodyPart: BodyPart, to outputStream: OutputStream) throws {\n        let headerData = encodeHeaders(for: bodyPart)\n        return try write(headerData, to: outputStream)\n    }\n\n    private func writeBodyStream(for bodyPart: BodyPart, to outputStream: OutputStream) throws {\n        let inputStream = bodyPart.bodyStream\n\n        inputStream.open()\n        defer { inputStream.close() }\n\n        while inputStream.hasBytesAvailable {\n            var buffer = [UInt8](repeating: 0, count: streamBufferSize)\n            let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize)\n\n            if let streamError = inputStream.streamError {\n                throw CLDNError.multipartEncodingFailed(reason: .inputStreamReadFailed(error: streamError))\n            }\n\n            if bytesRead > 0 {\n                if buffer.count != bytesRead {\n                    buffer = Array(buffer[0..<bytesRead])\n                }\n\n                try write(&buffer, to: outputStream)\n            } else {\n                break\n            }\n        }\n    }\n\n    private func writeFinalBoundaryData(for bodyPart: BodyPart, to outputStream: OutputStream) throws {\n        if bodyPart.hasFinalBoundary {\n            return try write(finalBoundaryData(), to: outputStream)\n        }\n    }\n\n    // MARK: - Private - Writing Buffered Data to Output Stream\n\n    private func write(_ data: Data, to outputStream: OutputStream) throws {\n        var buffer = [UInt8](repeating: 0, count: data.count)\n        data.copyBytes(to: &buffer, count: data.count)\n\n        return try write(&buffer, to: outputStream)\n    }\n\n    private func write(_ buffer: inout [UInt8], to outputStream: OutputStream) throws {\n        var bytesToWrite = buffer.count\n\n        while bytesToWrite > 0, outputStream.hasSpaceAvailable {\n            let bytesWritten = outputStream.write(buffer, maxLength: bytesToWrite)\n\n            if let error = outputStream.streamError {\n                throw CLDNError.multipartEncodingFailed(reason: .outputStreamWriteFailed(error: error))\n            }\n\n            bytesToWrite -= bytesWritten\n\n            if bytesToWrite > 0 {\n                buffer = Array(buffer[bytesWritten..<buffer.count])\n            }\n        }\n    }\n\n    // MARK: - Private - Mime Type\n\n    private func mimeType(forPathExtension pathExtension: String) -> String {\n        if\n            let id = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(),\n            let contentType = UTTypeCopyPreferredTagWithClass(id, kUTTagClassMIMEType)?.takeRetainedValue()\n        {\n            return contentType as String\n        }\n\n        return \"application/octet-stream\"\n    }\n\n    // MARK: - Private - Content Headers\n\n    private func contentHeaders(withName name: String, fileName: String? = nil, mimeType: String? = nil) -> [String: String] {\n        var disposition = \"form-data; name=\\\"\\(name)\\\"\"\n        if let fileName = fileName { disposition += \"; filename=\\\"\\(fileName)\\\"\" }\n\n        var headers = [\"Content-Disposition\": disposition]\n        if let mimeType = mimeType { headers[\"Content-Type\"] = mimeType }\n\n        return headers\n    }\n\n    // MARK: - Private - Boundary Encoding\n\n    private func initialBoundaryData() -> Data {\n        return BoundaryGenerator.boundaryData(forBoundaryType: .initial, boundary: boundary)\n    }\n\n    private func encapsulatedBoundaryData() -> Data {\n        return BoundaryGenerator.boundaryData(forBoundaryType: .encapsulated, boundary: boundary)\n    }\n\n    private func finalBoundaryData() -> Data {\n        return BoundaryGenerator.boundaryData(forBoundaryType: .final, boundary: boundary)\n    }\n\n    // MARK: - Private - Errors\n\n    private func setBodyPartError(withReason reason: CLDNError.MultipartEncodingFailureReason) {\n        guard bodyPartError == nil else { return }\n        bodyPartError = CLDNError.multipartEncodingFailed(reason: reason)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNParameterEncoding.swift",
    "content": "//\n//  CLDNParameterEncoding.swift\n//\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\nimport Foundation\n\n/// HTTP method definitions.\n///\n/// See https://tools.ietf.org/html/rfc7231#section-4.3\ninternal enum CLDNHTTPMethod: String {\n    case options = \"OPTIONS\"\n    case get     = \"GET\"\n    case head    = \"HEAD\"\n    case post    = \"POST\"\n    case put     = \"PUT\"\n    case patch   = \"PATCH\"\n    case delete  = \"DELETE\"\n    case trace   = \"TRACE\"\n    case connect = \"CONNECT\"\n}\n\n// MARK: -\n\n/// A dictionary of parameters to apply to a `URLRequest`.\ninternal typealias CLDNParameters = [String: Any]\n\n/// A type used to define how a set of parameters are applied to a `URLRequest`.\ninternal protocol CLDNParameterEncoding {\n    /// Creates a URL request by encoding parameters and applying them onto an existing request.\n    ///\n    /// - parameter urlRequest: The request to have parameters applied.\n    /// - parameter parameters: The parameters to apply.\n    ///\n    /// - throws: An `CLDNError.parameterEncodingFailed` error if encoding fails.\n    ///\n    /// - returns: The encoded request.\n    func CLDN_Encode(_ urlRequest: CLDNURLRequestConvertible, with parameters: CLDNParameters?) throws -> URLRequest\n}\n\n// MARK: -\n\n/// Creates a url-encoded query string to be set as or appended to any existing URL query string or set as the HTTP\n/// body of the URL request. Whether the query string is set or appended to any existing URL query string or set as\n/// the HTTP body depends on the destination of the encoding.\n///\n/// The `Content-Type` HTTP header field of an encoded request with HTTP body is set to\n/// `application/x-www-form-urlencoded; charset=utf-8`.\n///\n/// There is no published specification for how to encode collection types. By default the convention of appending\n/// `[]` to the key for array values (`foo[]=1&foo[]=2`), and appending the key surrounded by square brackets for\n/// nested dictionary values (`foo[bar]=baz`) is used. Optionally, `ArrayEncoding` can be used to omit the\n/// square brackets appended to array keys.\n///\n/// `BoolEncoding` can be used to configure how boolean values are encoded. The default behavior is to encode\n/// `true` as 1 and `false` as 0.\ninternal struct CLDNURLEncoding: CLDNParameterEncoding {\n\n    // MARK: Helper Types\n\n    /// Defines whether the url-encoded query string is applied to the existing query string or HTTP body of the\n    /// resulting URL request.\n    ///\n    /// - methodDependent: Applies encoded query string result to existing query string for `GET`, `HEAD` and `DELETE`\n    ///                    requests and sets as the HTTP body for requests with any other HTTP method.\n    /// - queryString:     Sets or appends encoded query string result to existing query string.\n    /// - httpBody:        Sets encoded query string result as the HTTP body of the URL request.\n    internal enum Destination {\n        case methodDependent, queryString, httpBody\n    }\n\n    /// Configures how `Array` parameters are encoded.\n    ///\n    /// - brackets:        An empty set of square brackets is appended to the key for every value.\n    ///                    This is the default behavior.\n    /// - noBrackets:      No brackets are appended. The key is encoded as is.\n    internal enum ArrayEncoding {\n        case brackets, noBrackets\n\n        func encode(key: String) -> String {\n            switch self {\n            case .brackets:\n                return \"\\(key)[]\"\n            case .noBrackets:\n                return key\n            }\n        }\n    }\n\n    /// Configures how `Bool` parameters are encoded.\n    ///\n    /// - numeric:         Encode `true` as `1` and `false` as `0`. This is the default behavior.\n    /// - literal:         Encode `true` and `false` as string literals.\n    internal enum BoolEncoding {\n        case numeric, literal\n\n        func encode(value: Bool) -> String {\n            switch self {\n            case .numeric:\n                return value ? \"1\" : \"0\"\n            case .literal:\n                return value ? \"true\" : \"false\"\n            }\n        }\n    }\n\n    // MARK: Properties\n\n    /// Returns a default `URLEncoding` instance.\n    internal static var `default`: CLDNURLEncoding { return CLDNURLEncoding() }\n\n    /// Returns a `URLEncoding` instance with a `.methodDependent` destination.\n    internal static var methodDependent: CLDNURLEncoding { return CLDNURLEncoding() }\n\n    /// Returns a `URLEncoding` instance with a `.queryString` destination.\n    internal static var queryString: CLDNURLEncoding { return CLDNURLEncoding(destination: .queryString) }\n\n    /// Returns a `URLEncoding` instance with an `.httpBody` destination.\n    internal static var httpBody: CLDNURLEncoding { return CLDNURLEncoding(destination: .httpBody) }\n\n    /// The destination defining where the encoded query string is to be applied to the URL request.\n    internal let destination: Destination\n\n    /// The encoding to use for `Array` parameters.\n    internal let arrayEncoding: ArrayEncoding\n\n    /// The encoding to use for `Bool` parameters.\n    internal let boolEncoding: BoolEncoding\n\n    // MARK: Initialization\n\n    /// Creates a `CLDNURLEncoding` instance using the specified destination.\n    ///\n    /// - parameter destination: The destination defining where the encoded query string is to be applied.\n    /// - parameter arrayEncoding: The encoding to use for `Array` parameters.\n    /// - parameter boolEncoding: The encoding to use for `Bool` parameters.\n    ///\n    /// - returns: The new `CLDNURLEncoding` instance.\n    internal init(destination: Destination = .methodDependent, arrayEncoding: ArrayEncoding = .brackets, boolEncoding: BoolEncoding = .numeric) {\n        self.destination = destination\n        self.arrayEncoding = arrayEncoding\n        self.boolEncoding = boolEncoding\n    }\n\n    // MARK: Encoding\n\n    /// Creates a URL request by encoding parameters and applying them onto an existing request.\n    ///\n    /// - parameter urlRequest: The request to have parameters applied.\n    /// - parameter parameters: The parameters to apply.\n    ///\n    /// - throws: An `Error` if the encoding process encounters an error.\n    ///\n    /// - returns: The encoded request.\n    internal func CLDN_Encode(_ urlRequest: CLDNURLRequestConvertible, with parameters: CLDNParameters?) throws -> URLRequest {\n        var urlRequest = try urlRequest.CLDN_AsURLRequest()\n\n        guard let parameters = parameters else { return urlRequest }\n\n        if let method = CLDNHTTPMethod(rawValue: urlRequest.httpMethod ?? \"GET\"), encodesParametersInURL(with: method) {\n            guard let url = urlRequest.url else {\n                throw CLDNError.parameterEncodingFailed(reason: .missingURL)\n            }\n\n            if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty {\n                let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + \"&\" } ?? \"\") + query(parameters)\n                urlComponents.percentEncodedQuery = percentEncodedQuery\n                urlRequest.url = urlComponents.url\n            }\n        } else {\n            if urlRequest.value(forHTTPHeaderField: \"Content-Type\") == nil {\n                urlRequest.setValue(\"application/x-www-form-urlencoded; charset=utf-8\", forHTTPHeaderField: \"Content-Type\")\n            }\n\n            urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)\n        }\n\n        return urlRequest\n    }\n\n    /// Creates percent-escaped, URL encoded query string components from the given key-value pair using recursion.\n    ///\n    /// - parameter key:   The key of the query component.\n    /// - parameter value: The value of the query component.\n    ///\n    /// - returns: The percent-escaped, URL encoded query string components.\n    internal func queryComponents(fromKey key: String, value: Any) -> [(String, String)] {\n        var components: [(String, String)] = []\n\n        if let dictionary = value as? [String: Any] {\n            for (nestedKey, value) in dictionary {\n                components += queryComponents(fromKey: \"\\(key)[\\(nestedKey)]\", value: value)\n            }\n        } else if let array = value as? [Any] {\n            for value in array {\n                components += queryComponents(fromKey: arrayEncoding.encode(key: key), value: value)\n            }\n        } else if let value = value as? NSNumber {\n            if value.isBool {\n                components.append((escape(key), escape(boolEncoding.encode(value: value.boolValue))))\n            } else {\n                components.append((escape(key), escape(\"\\(value)\")))\n            }\n        } else if let bool = value as? Bool {\n            components.append((escape(key), escape(boolEncoding.encode(value: bool))))\n        } else {\n            components.append((escape(key), escape(\"\\(value)\")))\n        }\n\n        return components\n    }\n\n    /// Returns a percent-escaped string following RFC 3986 for a query string key or value.\n    ///\n    /// RFC 3986 states that the following characters are \"reserved\" characters.\n    ///\n    /// - General Delimiters: \":\", \"#\", \"[\", \"]\", \"@\", \"?\", \"/\"\n    /// - Sub-Delimiters: \"!\", \"$\", \"&\", \"'\", \"(\", \")\", \"*\", \"+\", \",\", \";\", \"=\"\n    ///\n    /// In RFC 3986 - Section 3.4, it states that the \"?\" and \"/\" characters should not be escaped to allow\n    /// query strings to include a URL. Therefore, all \"reserved\" characters with the exception of \"?\" and \"/\"\n    /// should be percent-escaped in the query string.\n    ///\n    /// - parameter string: The string to be percent-escaped.\n    ///\n    /// - returns: The percent-escaped string.\n    internal func escape(_ string: String) -> String {\n        let generalDelimitersToEncode = \":#[]@\" // does not include \"?\" or \"/\" due to RFC 3986 - Section 3.4\n        let subDelimitersToEncode = \"!$&'()*+,;=\"\n\n        var allowedCharacterSet = CharacterSet.urlQueryAllowed\n        allowedCharacterSet.remove(charactersIn: \"\\(generalDelimitersToEncode)\\(subDelimitersToEncode)\")\n\n        var escaped = \"\"\n\n        //==========================================================================================================\n        //\n        //  Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few\n        //  hundred Chinese characters causes various malloc error crashes. To avoid this issue until iOS 8 is no\n        //  longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead. For more\n        //  info, please refer to:\n        //\n        //      - https://github.com/Alamofire/Alamofire/issues/206\n        //\n        //==========================================================================================================\n\n        if #available(iOS 8.3, *) {\n            escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string\n        } else {\n            let batchSize = 50\n            var index = string.startIndex\n\n            while index != string.endIndex {\n                let startIndex = index\n                let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex\n                let range = startIndex..<endIndex\n\n                let substring = string[range]\n\n                escaped += substring.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? String(substring)\n\n                index = endIndex\n            }\n        }\n\n        return escaped\n    }\n\n    private func query(_ parameters: [String: Any]) -> String {\n        var components: [(String, String)] = []\n\n        for key in parameters.keys.sorted(by: <) {\n            let value = parameters[key]!\n            components += queryComponents(fromKey: key, value: value)\n        }\n        return components.map { \"\\($0)=\\($1)\" }.joined(separator: \"&\")\n    }\n\n    private func encodesParametersInURL(with method: CLDNHTTPMethod) -> Bool {\n        switch destination {\n        case .queryString:\n            return true\n        case .httpBody:\n            return false\n        default:\n            break\n        }\n\n        switch method {\n        case .get, .head, .delete:\n            return true\n        default:\n            return false\n        }\n    }\n}\n\n// MARK: -\n\n/// Uses `JSONSerialization` to create a JSON representation of the parameters object, which is set as the body of the\n/// request. The `Content-Type` HTTP header field of an encoded request is set to `application/json`.\ninternal struct CLDNJSONEncoding: CLDNParameterEncoding {\n\n    // MARK: Properties\n\n    /// Returns a `JSONEncoding` instance with default writing options.\n    internal static var `default`: CLDNJSONEncoding { return CLDNJSONEncoding() }\n\n    /// Returns a `JSONEncoding` instance with `.prettyPrinted` writing options.\n    internal static var prettyPrinted: CLDNJSONEncoding { return CLDNJSONEncoding(options: .prettyPrinted) }\n\n    /// The options for writing the parameters as JSON data.\n    internal let options: JSONSerialization.WritingOptions\n\n    // MARK: Initialization\n\n    /// Creates a `CLDNJSONEncoding` instance using the specified options.\n    ///\n    /// - parameter options: The options for writing the parameters as JSON data.\n    ///\n    /// - returns: The new `CLDNJSONEncoding` instance.\n    internal init(options: JSONSerialization.WritingOptions = []) {\n        self.options = options\n    }\n\n    // MARK: Encoding\n\n    /// Creates a URL request by encoding parameters and applying them onto an existing request.\n    ///\n    /// - parameter urlRequest: The request to have parameters applied.\n    /// - parameter parameters: The parameters to apply.\n    ///\n    /// - throws: An `Error` if the encoding process encounters an error.\n    ///\n    /// - returns: The encoded request.\n    internal func CLDN_Encode(_ urlRequest: CLDNURLRequestConvertible, with parameters: CLDNParameters?) throws -> URLRequest {\n        var urlRequest = try urlRequest.CLDN_AsURLRequest()\n\n        guard let parameters = parameters else { return urlRequest }\n\n        do {\n            let data = try JSONSerialization.data(withJSONObject: parameters, options: options)\n\n            if urlRequest.value(forHTTPHeaderField: \"Content-Type\") == nil {\n                urlRequest.setValue(\"application/json\", forHTTPHeaderField: \"Content-Type\")\n            }\n\n            urlRequest.httpBody = data\n        } catch {\n            throw CLDNError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))\n        }\n\n        return urlRequest\n    }\n\n    /// Creates a URL request by encoding the JSON object and setting the resulting data on the HTTP body.\n    ///\n    /// - parameter urlRequest: The request to apply the JSON object to.\n    /// - parameter jsonObject: The JSON object to apply to the request.\n    ///\n    /// - throws: An `Error` if the encoding process encounters an error.\n    ///\n    /// - returns: The encoded request.\n    internal func encode(_ urlRequest: CLDNURLRequestConvertible, withJSONObject jsonObject: Any? = nil) throws -> URLRequest {\n        var urlRequest = try urlRequest.CLDN_AsURLRequest()\n\n        guard let jsonObject = jsonObject else { return urlRequest }\n\n        do {\n            let data = try JSONSerialization.data(withJSONObject: jsonObject, options: options)\n\n            if urlRequest.value(forHTTPHeaderField: \"Content-Type\") == nil {\n                urlRequest.setValue(\"application/json\", forHTTPHeaderField: \"Content-Type\")\n            }\n\n            urlRequest.httpBody = data\n        } catch {\n            throw CLDNError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))\n        }\n\n        return urlRequest\n    }\n}\n\n// MARK: -\n\nextension NSNumber {\n    fileprivate var isBool: Bool { return CFBooleanGetTypeID() == CFGetTypeID(self) }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNRequest.swift",
    "content": "//\n//  CLDNRequest.swift\n//\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\nimport Foundation\n\n/// A type that can inspect and optionally adapt a `URLRequest` in some manner if necessary.\ninternal protocol CLDNRequestAdapter {\n    /// Inspects and adapts the specified `URLRequest` in some manner if necessary and returns the result.\n    ///\n    /// - parameter urlRequest: The URL request to adapt.\n    ///\n    /// - throws: An `Error` if the adaptation encounters an error.\n    ///\n    /// - returns: The adapted `URLRequest`.\n    func CLDN_Adapt(_ urlRequest: URLRequest) throws -> URLRequest\n}\n\n// MARK: -\n\n/// A closure executed when the `CLDNRequestRetrier` determines whether a `CLDNRequest` should be retried or not.\ninternal typealias CLDNRequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval) -> Void\n\n/// A type that determines whether a request should be retried after being executed by the specified session manager\n/// and encountering an error.\ninternal protocol CLDNRequestRetrier {\n    /// Determines whether the `CLDNRequest` should be retried by calling the `completion` closure.\n    ///\n    /// This operation is fully asynchronous. Any amount of time can be taken to determine whether the request needs\n    /// to be retried. The one requirement is that the completion closure is called to ensure the request is properly\n    /// cleaned up after.\n    ///\n    /// - parameter manager:    The session manager the request was executed on.\n    /// - parameter request:    The request that failed due to the encountered error.\n    /// - parameter error:      The error encountered when executing the request.\n    /// - parameter completion: The completion closure to be executed when retry decision has been determined.\n    func CLDN_Should(_ manager: CLDNSessionManager, retry request: CLDNRequest, with error: Error, completion: @escaping CLDNRequestRetryCompletion)\n}\n\n// MARK: -\n\nprotocol CLDNTaskConvertible {\n    func CLDN_Task(session: URLSession, adapter: CLDNRequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask\n}\n\n/// A dictionary of headers to apply to a `URLRequest`.\ninternal typealias CLDNHTTPHeaders = [String: String]\n\n// MARK: -\n\n/// Responsible for sending a request and receiving the response and associated data from the server, as well as\n/// managing its underlying `URLSessionTask`.\ninternal class CLDNRequest {\n\n    // MARK: Helper Types\n\n    /// A closure executed when monitoring upload or download progress of a request.\n    internal typealias ProgressHandler = (Progress) -> Void\n\n    enum RequestTask {\n        case data(CLDNTaskConvertible?, URLSessionTask?)\n        case upload(CLDNTaskConvertible?, URLSessionTask?)\n    }\n\n    // MARK: Properties\n\n    /// The delegate for the underlying task.\n    internal var delegate: CLDNTaskDelegate {\n        get {\n            taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }\n            return taskDelegate\n        }\n        set {\n            taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }\n            taskDelegate = newValue\n        }\n    }\n\n    /// The underlying task.\n    internal var task: URLSessionTask? { return delegate.task }\n\n    /// The session belonging to the underlying task.\n    internal let session: URLSession\n\n    /// The request sent or to be sent to the server.\n    internal var request: URLRequest? { return task?.originalRequest }\n\n    /// The response received from the server, if any.\n    internal var response: HTTPURLResponse? { return task?.response as? HTTPURLResponse }\n\n    /// The number of times the request has been retried.\n    internal var retryCount: UInt = 0\n\n    let originalTask: CLDNTaskConvertible?\n\n    var startTime: CFAbsoluteTime?\n    var endTime: CFAbsoluteTime?\n\n    var validations: [() -> Void] = []\n\n    private var taskDelegate: CLDNTaskDelegate\n    private var taskDelegateLock = NSLock()\n\n    // MARK: Lifecycle\n\n    init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {\n        self.session = session\n\n        switch requestTask {\n        case .data(let originalTask, let task):\n            taskDelegate = CLDNDataTaskDelegate(task: task)\n            self.originalTask = originalTask\n        case .upload(let originalTask, let task):\n            taskDelegate = CLDNUploadTaskDelegate(task: task)\n            self.originalTask = originalTask\n        }\n\n        delegate.error = error\n        delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }\n    }\n\n    // MARK: Authentication\n\n    /// Associates an HTTP Basic credential with the request.\n    ///\n    /// - parameter user:        The user.\n    /// - parameter password:    The password.\n    /// - parameter persistence: The URL credential persistence. `.ForSession` by default.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func authenticate(\n        user: String,\n        password: String,\n        persistence: URLCredential.Persistence = .forSession)\n        -> Self\n    {\n        let credential = URLCredential(user: user, password: password, persistence: persistence)\n        return authenticate(usingCredential: credential)\n    }\n\n    /// Associates a specified credential with the request.\n    ///\n    /// - parameter credential: The credential.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func authenticate(usingCredential credential: URLCredential) -> Self {\n        delegate.credential = credential\n        return self\n    }\n\n    /// Returns a base64 encoded basic authentication credential as an authorization header tuple.\n    ///\n    /// - parameter user:     The user.\n    /// - parameter password: The password.\n    ///\n    /// - returns: A tuple with Authorization header and credential value if encoding succeeds, `nil` otherwise.\n    internal class func authorizationHeader(user: String, password: String) -> (key: String, value: String)? {\n        guard let data = \"\\(user):\\(password)\".data(using: .utf8) else { return nil }\n\n        let credential = data.base64EncodedString(options: [])\n\n        return (key: \"Authorization\", value: \"Basic \\(credential)\")\n    }\n\n    // MARK: State\n\n    /// Resumes the request.\n    internal func resume() {\n        guard let task = task else { delegate.queue.isSuspended = false ; return }\n\n        if startTime == nil { startTime = CFAbsoluteTimeGetCurrent() }\n\n        task.resume()\n\n//        NotificationCenter.default.post(\n//            name: Notification.Name.Task.DidResume,\n//            object: self,\n//            userInfo: [Notification.Key.Task: task]\n//        )\n    }\n\n    /// Suspends the request.\n    internal func suspend() {\n        guard let task = task else { return }\n\n        task.suspend()\n    }\n\n    /// Cancels the request.\n    internal func cancel() {\n        guard let task = task else { return }\n\n        task.cancel()\n    }\n}\n\n// MARK: - CustomStringConvertible\n\nextension CLDNRequest: CustomStringConvertible {\n    /// The textual representation used when written to an output stream, which includes the HTTP method and URL, as\n    /// well as the response status code if a response has been received.\n    internal var description: String {\n        var components: [String] = []\n\n        if let HTTPMethod = request?.httpMethod {\n            components.append(HTTPMethod)\n        }\n\n        if let urlString = request?.url?.absoluteString {\n            components.append(urlString)\n        }\n\n        if let response = response {\n            components.append(\"(\\(response.statusCode))\")\n        }\n\n        return components.joined(separator: \" \")\n    }\n}\n\n// MARK: - CustomDebugStringConvertible\n\nextension CLDNRequest: CustomDebugStringConvertible {\n    /// The textual representation used when written to an output stream, in the form of a cURL command.\n    internal var debugDescription: String {\n        return cURLRepresentation()\n    }\n\n    func cURLRepresentation() -> String {\n        var components = [\"$ curl -v\"]\n\n        guard let request = self.request,\n              let url = request.url,\n              let host = url.host\n        else {\n            return \"$ curl command could not be created\"\n        }\n\n        if let httpMethod = request.httpMethod, httpMethod != \"GET\" {\n            components.append(\"-X \\(httpMethod)\")\n        }\n\n        if let credentialStorage = self.session.configuration.urlCredentialStorage {\n            let protectionSpace = URLProtectionSpace(\n                host: host,\n                port: url.port ?? 0,\n                protocol: url.scheme,\n                realm: host,\n                authenticationMethod: NSURLAuthenticationMethodHTTPBasic\n            )\n\n            if let credentials = credentialStorage.credentials(for: protectionSpace)?.values {\n                for credential in credentials {\n                    guard let user = credential.user, let password = credential.password else { continue }\n                    components.append(\"-u \\(user):\\(password)\")\n                }\n            } else {\n                if let credential = delegate.credential, let user = credential.user, let password = credential.password {\n                    components.append(\"-u \\(user):\\(password)\")\n                }\n            }\n        }\n\n        if session.configuration.httpShouldSetCookies {\n            if\n                let cookieStorage = session.configuration.httpCookieStorage,\n                let cookies = cookieStorage.cookies(for: url), !cookies.isEmpty\n            {\n                let string = cookies.reduce(\"\") { $0 + \"\\($1.name)=\\($1.value);\" }\n\n            #if swift(>=3.2)\n                components.append(\"-b \\\"\\(string[..<string.index(before: string.endIndex)])\\\"\")\n            #else\n                components.append(\"-b \\\"\\(string.substring(to: string.characters.index(before: string.endIndex)))\\\"\")\n            #endif\n            }\n        }\n\n        var headers: [AnyHashable: Any] = [:]\n\n        session.configuration.httpAdditionalHeaders?.filter {  $0.0 != AnyHashable(\"Cookie\") }\n                                                    .forEach { headers[$0.0] = $0.1 }\n\n        request.allHTTPHeaderFields?.filter { $0.0 != \"Cookie\" }\n                                    .forEach { headers[$0.0] = $0.1 }\n\n        components += headers.map {\n            let escapedValue = String(describing: $0.value).replacingOccurrences(of: \"\\\"\", with: \"\\\\\\\"\")\n\n            return \"-H \\\"\\($0.key): \\(escapedValue)\\\"\"\n        }\n\n        if let httpBodyData = request.httpBody, let httpBody = String(data: httpBodyData, encoding: .utf8) {\n            var escapedBody = httpBody.replacingOccurrences(of: \"\\\\\\\"\", with: \"\\\\\\\\\\\"\")\n            escapedBody = escapedBody.replacingOccurrences(of: \"\\\"\", with: \"\\\\\\\"\")\n\n            components.append(\"-d \\\"\\(escapedBody)\\\"\")\n        }\n\n        components.append(\"\\\"\\(url.absoluteString)\\\"\")\n\n        return components.joined(separator: \" \\\\\\n\\t\")\n    }\n}\n\n// MARK: -\n\n/// Specific type of `CLDNRequest` that manages an underlying `URLSessionDataTask`.\ninternal class CLDNDataRequest: CLDNRequest {\n\n    // MARK: Helper Types\n\n    struct Requestable: CLDNTaskConvertible {\n        let urlRequest: URLRequest\n\n        func CLDN_Task(session: URLSession, adapter: CLDNRequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {\n            do {\n                let urlRequest = try self.urlRequest.adapt(using: adapter)\n                return queue.sync { session.dataTask(with: urlRequest) }\n            } catch {\n                throw AdaptError(error: error)\n            }\n        }\n    }\n\n    // MARK: Properties\n\n    /// The request sent or to be sent to the server.\n    internal override var request: URLRequest? {\n        if let request = super.request { return request }\n        if let requestable = originalTask as? Requestable { return requestable.urlRequest }\n\n        return nil\n    }\n\n    /// The progress of fetching the response data from the server for the request.\n    internal var progress: Progress { return dataDelegate.progress }\n\n    var dataDelegate: CLDNDataTaskDelegate { return delegate as! CLDNDataTaskDelegate }\n\n    // MARK: Stream\n\n    /// Sets a closure to be called periodically during the lifecycle of the request as data is read from the server.\n    ///\n    /// This closure returns the bytes most recently received from the server, not including data from previous calls.\n    /// If this closure is set, data will only be available within this closure, and will not be saved elsewhere. It is\n    /// also important to note that the server data in any `Response` object will be `nil`.\n    ///\n    /// - parameter closure: The code to be executed periodically during the lifecycle of the request.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func stream(closure: ((Data) -> Void)? = nil) -> Self {\n        dataDelegate.dataStream = closure\n        return self\n    }\n\n    // MARK: Progress\n\n    /// Sets a closure to be called periodically during the lifecycle of the `CLDNRequest` as data is read from the server.\n    ///\n    /// - parameter queue:   The dispatch queue to execute the closure on.\n    /// - parameter closure: The code to be executed periodically as data is read from the server.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func downloadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self {\n        dataDelegate.progressHandler = (closure, queue)\n        return self\n    }\n}\n\n// MARK: -\n\n/// Specific type of `CLDNRequest` that manages an underlying `URLSessionUploadTask`.\ninternal class CLDNUploadRequest: CLDNDataRequest {\n\n    // MARK: Helper Types\n\n    enum Uploadable: CLDNTaskConvertible {\n        case data(Data, URLRequest)\n        case file(URL, URLRequest)\n        case stream(InputStream, URLRequest)\n\n        func CLDN_Task(session: URLSession, adapter: CLDNRequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {\n            do {\n                let task: URLSessionTask\n\n                switch self {\n                case let .data(data, urlRequest):\n                    let urlRequest = try urlRequest.adapt(using: adapter)\n                    task = queue.sync { session.uploadTask(with: urlRequest, from: data) }\n                case let .file(url, urlRequest):\n                    let urlRequest = try urlRequest.adapt(using: adapter)\n                    task = queue.sync { session.uploadTask(with: urlRequest, fromFile: url) }\n                case let .stream(_, urlRequest):\n                    let urlRequest = try urlRequest.adapt(using: adapter)\n                    task = queue.sync { session.uploadTask(withStreamedRequest: urlRequest) }\n                }\n\n                return task\n            } catch {\n                throw AdaptError(error: error)\n            }\n        }\n    }\n\n    // MARK: Properties\n\n    /// The request sent or to be sent to the server.\n    internal override var request: URLRequest? {\n        if let request = super.request { return request }\n\n        guard let uploadable = originalTask as? Uploadable else { return nil }\n\n        switch uploadable {\n        case .data(_, let urlRequest), .file(_, let urlRequest), .stream(_, let urlRequest):\n            return urlRequest\n        }\n    }\n\n    /// The progress of uploading the payload to the server for the upload request.\n    internal var uploadProgress: Progress { return uploadDelegate.uploadProgress }\n\n    var uploadDelegate: CLDNUploadTaskDelegate { return delegate as! CLDNUploadTaskDelegate }\n\n    // MARK: Upload Progress\n\n    /// Sets a closure to be called periodically during the lifecycle of the `CLDNUploadRequest` as data is sent to\n    /// the server.\n    ///\n    /// After the data is sent to the server, the `progress(queue:closure:)` APIs can be used to monitor the progress\n    /// of data being read from the server.\n    ///\n    /// - parameter queue:   The dispatch queue to execute the closure on.\n    /// - parameter closure: The code to be executed periodically as data is sent to the server.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func uploadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self {\n        uploadDelegate.uploadProgressHandler = (closure, queue)\n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNResponse.swift",
    "content": "//\n//  CLDNResponse.swift\n//\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\nimport Foundation\n\n/// Used to store all data associated with an non-serialized response of a data or upload request.\ninternal struct CLDNDefaultDataResponse {\n    /// The URL request sent to the server.\n    internal let request: URLRequest?\n\n    /// The server's response to the URL request.\n    internal let response: HTTPURLResponse?\n\n    /// The data returned by the server.\n    internal let data: Data?\n\n    /// The error encountered while executing or validating the request.\n    internal let error: Error?\n\n    /// The timeline of the complete lifecycle of the request.\n    internal let timeline: CLDNTimeline\n\n    var _metrics: AnyObject?\n\n    /// Creates a `CLDNDefaultDataResponse` instance from the specified parameters.\n    ///\n    /// - Parameters:\n    ///   - request:  The URL request sent to the server.\n    ///   - response: The server's response to the URL request.\n    ///   - data:     The data returned by the server.\n    ///   - error:    The error encountered while executing or validating the request.\n    ///   - timeline: The timeline of the complete lifecycle of the request. `CLDNTimeline()` by default.\n    ///   - metrics:  The task metrics containing the request / response statistics. `nil` by default.\n    internal init(\n        request: URLRequest?,\n        response: HTTPURLResponse?,\n        data: Data?,\n        error: Error?,\n        timeline: CLDNTimeline = CLDNTimeline(),\n        metrics: AnyObject? = nil)\n    {\n        self.request = request\n        self.response = response\n        self.data = data\n        self.error = error\n        self.timeline = timeline\n    }\n}\n\n// MARK: -\n\n/// Used to store all data associated with a serialized response of a data or upload request.\ninternal struct CLDNDataResponse<Value> {\n    /// The URL request sent to the server.\n    internal let request: URLRequest?\n\n    /// The server's response to the URL request.\n    internal let response: HTTPURLResponse?\n\n    /// The data returned by the server.\n    internal let data: Data?\n\n    /// The result of response serialization.\n    internal let result: CLDNResult<Value>\n\n    /// The timeline of the complete lifecycle of the request.\n    internal let timeline: CLDNTimeline\n\n    /// Returns the associated value of the result if it is a success, `nil` otherwise.\n    internal var value: Value? { return result.value }\n\n    /// Returns the associated error value if the result if it is a failure, `nil` otherwise.\n    internal var error: Error? { return result.error }\n\n    var _metrics: AnyObject?\n\n    /// Creates a `CLDNDataResponse` instance with the specified parameters derived from response serialization.\n    ///\n    /// - parameter request:  The URL request sent to the server.\n    /// - parameter response: The server's response to the URL request.\n    /// - parameter data:     The data returned by the server.\n    /// - parameter result:   The result of response serialization.\n    /// - parameter timeline: The timeline of the complete lifecycle of the `CLDNRequest`. Defaults to `CLDNTimeline()`.\n    ///\n    /// - returns: The new `CLDNDataResponse` instance.\n    internal init(\n        request: URLRequest?,\n        response: HTTPURLResponse?,\n        data: Data?,\n        result: CLDNResult<Value>,\n        timeline: CLDNTimeline = CLDNTimeline())\n    {\n        self.request = request\n        self.response = response\n        self.data = data\n        self.result = result\n        self.timeline = timeline\n    }\n}\n\n// MARK: -\n\nextension CLDNDataResponse: CustomStringConvertible, CustomDebugStringConvertible {\n    /// The textual representation used when written to an output stream, which includes whether the result was a\n    /// success or failure.\n    internal var description: String {\n        return result.debugDescription\n    }\n\n    /// The debug textual representation used when written to an output stream, which includes the URL request, the URL\n    /// response, the server data, the response serialization result and the timeline.\n    internal var debugDescription: String {\n        let requestDescription = request.map { \"\\($0.httpMethod ?? \"GET\") \\($0)\"} ?? \"nil\"\n        let requestBody = request?.httpBody.map { String(decoding: $0, as: UTF8.self) } ?? \"None\"\n        let responseDescription = response.map { \"\\($0)\" } ?? \"nil\"\n        let responseBody = data.map { String(decoding: $0, as: UTF8.self) } ?? \"None\"\n\n        return \"\"\"\n        [Request]: \\(requestDescription)\n        [Request Body]: \\n\\(requestBody)\n        [Response]: \\(responseDescription)\n        [Response Body]: \\n\\(responseBody)\n        [Result]: \\(result)\n        [Timeline]: \\(timeline.debugDescription)\n        \"\"\"\n    }\n}\n\n// MARK: -\n\nprotocol CLDNResponse {\n    /// The task metrics containing the request / response statistics.\n    var _metrics: AnyObject? { get set }\n    mutating func CLDN_Add(_ metrics: AnyObject?)\n}\n\nextension CLDNResponse {\n    mutating func CLDN_Add(_ metrics: AnyObject?) {\n        #if !os(watchOS)\n            guard #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) else { return }\n            guard let metrics = metrics as? URLSessionTaskMetrics else { return }\n\n            _metrics = metrics\n        #endif\n    }\n}\n\n// MARK: -\n\n@available(iOS 10.0, macOS 10.12, tvOS 10.0, *)\nextension CLDNDefaultDataResponse: CLDNResponse {\n#if !os(watchOS)\n    /// The task metrics containing the request / response statistics.\n    internal var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }\n#endif\n}\n\n@available(iOS 10.0, macOS 10.12, tvOS 10.0, *)\nextension CLDNDataResponse: CLDNResponse {\n#if !os(watchOS)\n    /// The task metrics containing the request / response statistics.\n    internal var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }\n#endif\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNResponseSerialization.swift",
    "content": "//\n//  CLDNResponseSerialization.swift\n//\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\nimport Foundation\n\n/// The type in which all data response serializers must conform to in order to serialize a response.\ninternal protocol CLDNDataResponseSerializerProtocol {\n    /// The type of serialized object to be created by this `DataResponseSerializerType`.\n    associatedtype SerializedObject\n\n    /// A closure used by response handlers that takes a request, response, data and error and returns a result.\n    var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> CLDNResult<SerializedObject> { get }\n}\n\n// MARK: -\n\n/// A generic `DataResponseSerializerType` used to serialize a request, response, and data into a serialized object.\ninternal struct CLDNDataResponseSerializer<Value>: CLDNDataResponseSerializerProtocol {\n    /// The type of serialized object to be created by this `CLDNDataResponseSerializer`.\n    internal typealias SerializedObject = Value\n\n    /// A closure used by response handlers that takes a request, response, data and error and returns a result.\n    internal var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> CLDNResult<Value>\n\n    /// Initializes the `ResponseSerializer` instance with the given serialize response closure.\n    ///\n    /// - parameter serializeResponse: The closure used to serialize the response.\n    ///\n    /// - returns: The new generic response serializer instance.\n    internal init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, Data?, Error?) -> CLDNResult<Value>) {\n        self.serializeResponse = serializeResponse\n    }\n}\n\n// MARK: - Timeline\n\nextension CLDNRequest {\n    var timeline: CLDNTimeline {\n        let requestStartTime = self.startTime ?? CFAbsoluteTimeGetCurrent()\n        let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()\n        let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime\n\n        return CLDNTimeline(\n            requestStartTime: requestStartTime,\n            initialResponseTime: initialResponseTime,\n            requestCompletedTime: requestCompletedTime,\n            serializationCompletedTime: CFAbsoluteTimeGetCurrent()\n        )\n    }\n}\n\n// MARK: - Default\n\nextension CLDNDataRequest {\n    /// Adds a handler to be called once the request has finished.\n    ///\n    /// - parameter queue:             The queue on which the completion handler is dispatched.\n    /// - parameter completionHandler: The code to be executed once the request has finished.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func response(queue: DispatchQueue? = nil, completionHandler: @escaping (CLDNDefaultDataResponse) -> Void) -> Self {\n        delegate.queue.addOperation {\n            (queue ?? DispatchQueue.main).async {\n                var dataResponse = CLDNDefaultDataResponse(\n                    request: self.request,\n                    response: self.response,\n                    data: self.delegate.data,\n                    error: self.delegate.error,\n                    timeline: self.timeline\n                )\n\n                if #available(iOS 10.0, *)\n                {\n                    dataResponse.CLDN_Add(self.delegate.metrics)\n                }\n\n                completionHandler(dataResponse)\n            }\n        }\n\n        return self\n    }\n\n    /// Adds a handler to be called once the request has finished.\n    ///\n    /// - parameter queue:              The queue on which the completion handler is dispatched.\n    /// - parameter responseSerializer: The response serializer responsible for serializing the request, response,\n    ///                                 and data.\n    /// - parameter completionHandler:  The code to be executed once the request has finished.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func response<T: CLDNDataResponseSerializerProtocol>(\n        queue: DispatchQueue? = nil,\n        responseSerializer: T,\n        completionHandler: @escaping (CLDNDataResponse<T.SerializedObject>) -> Void)\n        -> Self\n    {\n        delegate.queue.addOperation {\n            let result = responseSerializer.serializeResponse(\n                self.request,\n                self.response,\n                self.delegate.data,\n                self.delegate.error\n            )\n\n            var dataResponse = CLDNDataResponse<T.SerializedObject>(\n                request: self.request,\n                response: self.response,\n                data: self.delegate.data,\n                result: result,\n                timeline: self.timeline\n            )\n            \n            if #available(iOS 10.0, *)\n            {\n                dataResponse.CLDN_Add(self.delegate.metrics)\n            }\n\n            (queue ?? DispatchQueue.main).async { completionHandler(dataResponse) }\n        }\n\n        return self\n    }\n}\n\n// MARK: - Data\n\nextension CLDNRequest {\n    /// Returns a result data type that contains the response data as-is.\n    ///\n    /// - parameter response: The response from the server.\n    /// - parameter data:     The data returned from the server.\n    /// - parameter error:    The error already encountered if it exists.\n    ///\n    /// - returns: The result data type.\n    internal static func serializeResponseData(response: HTTPURLResponse?, data: Data?, error: Error?) -> CLDNResult<Data> {\n        guard error == nil else { return .failure(error!) }\n\n        if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(Data()) }\n\n        guard let validData = data else {\n            if let statusCode = response?.statusCode,\n               let httpStatusCode = HTTPStatusCode(rawValue: statusCode), httpStatusCode.isError {\n                return .failure(CLDError.error(code: statusCode, userInfo: [\"message\": httpStatusCode.localizedReason]))\n            }\n            return .failure(CLDNError.responseSerializationFailed(reason: .inputDataNil))\n        }\n\n        return .success(validData)\n    }\n}\n\nextension CLDNDataRequest {\n    /// Creates a response serializer that returns the associated data as-is.\n    ///\n    /// - returns: A data response serializer.\n    internal static func dataResponseSerializer() -> CLDNDataResponseSerializer<Data> {\n        return CLDNDataResponseSerializer { _, response, data, error in\n            return CLDNRequest.serializeResponseData(response: response, data: data, error: error)\n        }\n    }\n\n    /// Adds a handler to be called once the request has finished.\n    ///\n    /// - parameter completionHandler: The code to be executed once the request has finished.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func responseData(\n        queue: DispatchQueue? = nil,\n        completionHandler: @escaping (CLDNDataResponse<Data>) -> Void)\n        -> Self\n    {\n        return response(\n            queue: queue,\n            responseSerializer: CLDNDataRequest.dataResponseSerializer(),\n            completionHandler: completionHandler\n        )\n    }\n}\n\n// MARK: - String\n\nextension CLDNRequest {\n    /// Returns a result string type initialized from the response data with the specified string encoding.\n    ///\n    /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server\n    ///                       response, falling back to the default HTTP default character set, ISO-8859-1.\n    /// - parameter response: The response from the server.\n    /// - parameter data:     The data returned from the server.\n    /// - parameter error:    The error already encountered if it exists.\n    ///\n    /// - returns: The result data type.\n    internal static func serializeResponseString(\n        encoding: String.Encoding?,\n        response: HTTPURLResponse?,\n        data: Data?,\n        error: Error?)\n        -> CLDNResult<String>\n    {\n        guard error == nil else { return .failure(error!) }\n\n        if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(\"\") }\n\n        guard let validData = data else {\n            return .failure(CLDNError.responseSerializationFailed(reason: .inputDataNil))\n        }\n\n        var convertedEncoding = encoding\n\n        if let encodingName = response?.textEncodingName as CFString?, convertedEncoding == nil {\n            convertedEncoding = String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(\n                CFStringConvertIANACharSetNameToEncoding(encodingName))\n            )\n        }\n\n        let actualEncoding = convertedEncoding ?? .isoLatin1\n\n        if let string = String(data: validData, encoding: actualEncoding) {\n            return .success(string)\n        } else {\n            if let statusCode = response?.statusCode,\n                let httpStatusCode = HTTPStatusCode(rawValue: statusCode), httpStatusCode.isError {\n                return .failure(CLDError.error(code: statusCode, userInfo: [\"message\": httpStatusCode.localizedReason]))\n            }\n            return .failure(CLDNError.responseSerializationFailed(reason: .stringSerializationFailed(encoding: actualEncoding)))\n        }\n    }\n}\n\nextension CLDNDataRequest {\n    /// Creates a response serializer that returns a result string type initialized from the response data with\n    /// the specified string encoding.\n    ///\n    /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server\n    ///                       response, falling back to the default HTTP default character set, ISO-8859-1.\n    ///\n    /// - returns: A string response serializer.\n    internal static func stringResponseSerializer(encoding: String.Encoding? = nil) -> CLDNDataResponseSerializer<String> {\n        return CLDNDataResponseSerializer { _, response, data, error in\n            return CLDNRequest.serializeResponseString(encoding: encoding, response: response, data: data, error: error)\n        }\n    }\n\n    /// Adds a handler to be called once the request has finished.\n    ///\n    /// - parameter encoding:          The string encoding. If `nil`, the string encoding will be determined from the\n    ///                                server response, falling back to the default HTTP default character set,\n    ///                                ISO-8859-1.\n    /// - parameter completionHandler: A closure to be executed once the request has finished.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func responseString(\n        queue: DispatchQueue? = nil,\n        encoding: String.Encoding? = nil,\n        completionHandler: @escaping (CLDNDataResponse<String>) -> Void)\n        -> Self\n    {\n        return response(\n            queue: queue,\n            responseSerializer: CLDNDataRequest.stringResponseSerializer(encoding: encoding),\n            completionHandler: completionHandler\n        )\n    }\n}\n\n// MARK: - JSON\n\nextension CLDNRequest {\n    /// Returns a JSON object contained in a result type constructed from the response data using `JSONSerialization`\n    /// with the specified reading options.\n    ///\n    /// - parameter options:  The JSON serialization reading options. Defaults to `.allowFragments`.\n    /// - parameter response: The response from the server.\n    /// - parameter data:     The data returned from the server.\n    /// - parameter error:    The error already encountered if it exists.\n    ///\n    /// - returns: The result data type.\n    internal static func serializeResponseJSON(\n        options: JSONSerialization.ReadingOptions,\n        response: HTTPURLResponse?,\n        data: Data?,\n        error: Error?)\n        -> CLDNResult<Any>\n    {\n        guard error == nil else { return .failure(error!) }\n\n        if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(NSNull()) }\n\n        guard let validData = data, validData.count > 0 else {\n            return .failure(CLDNError.responseSerializationFailed(reason: .inputDataNilOrZeroLength))\n        }\n\n        do {\n            let json = try JSONSerialization.jsonObject(with: validData, options: options)\n            return .success(json)\n        } catch {\n            if let statusCode = response?.statusCode,\n                let httpStatusCode = HTTPStatusCode(rawValue: statusCode), httpStatusCode.isError {\n                return .failure(CLDError.error(code: statusCode, userInfo: [\"message\": httpStatusCode.localizedReason]))\n            }\n            return .failure(CLDNError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error)))\n        }\n    }\n}\n\nextension CLDNDataRequest {\n    /// Creates a response serializer that returns a JSON object result type constructed from the response data using\n    /// `JSONSerialization` with the specified reading options.\n    ///\n    /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.\n    ///\n    /// - returns: A JSON object response serializer.\n    internal static func jsonResponseSerializer(\n        options: JSONSerialization.ReadingOptions = .allowFragments)\n        -> CLDNDataResponseSerializer<Any>\n    {\n        return CLDNDataResponseSerializer { _, response, data, error in\n            return CLDNRequest.serializeResponseJSON(options: options, response: response, data: data, error: error)\n        }\n    }\n\n    /// Adds a handler to be called once the request has finished.\n    ///\n    /// - parameter options:           The JSON serialization reading options. Defaults to `.allowFragments`.\n    /// - parameter completionHandler: A closure to be executed once the request has finished.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func responseJSON(\n        queue: DispatchQueue? = nil,\n        options: JSONSerialization.ReadingOptions = .allowFragments,\n        completionHandler: @escaping (CLDNDataResponse<Any>) -> Void)\n        -> Self\n    {\n        return response(\n            queue: queue,\n            responseSerializer: CLDNDataRequest.jsonResponseSerializer(options: options),\n            completionHandler: completionHandler\n        )\n    }\n}\n\n/// A set of HTTP response status code that do not contain response data.\nprivate let emptyDataStatusCodes: Set<Int> = [204, 205]\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNResult.swift",
    "content": "//\n//  CLDNResult.swift\n//\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\nimport Foundation\n\n/// Used to represent whether a request was successful or encountered an error.\n///\n/// - success: The request and all post processing operations were successful resulting in the serialization of the\n///            provided associated value.\n///\n/// - failure: The request encountered an error resulting in a failure. The associated values are the original data\n///            provided by the server as well as the error that caused the failure.\ninternal enum CLDNResult<Value> {\n    case success(Value)\n    case failure(Error)\n\n    /// Returns `true` if the result is a success, `false` otherwise.\n    internal var isSuccess: Bool {\n        switch self {\n        case .success:\n            return true\n        case .failure:\n            return false\n        }\n    }\n\n    /// Returns `true` if the result is a failure, `false` otherwise.\n    internal var isFailure: Bool {\n        return !isSuccess\n    }\n\n    /// Returns the associated value if the result is a success, `nil` otherwise.\n    internal var value: Value? {\n        switch self {\n        case .success(let value):\n            return value\n        case .failure:\n            return nil\n        }\n    }\n\n    /// Returns the associated error value if the result is a failure, `nil` otherwise.\n    internal var error: Error? {\n        switch self {\n        case .success:\n            return nil\n        case .failure(let error):\n            return error\n        }\n    }\n}\n\n// MARK: - CustomStringConvertible\n\nextension CLDNResult: CustomStringConvertible {\n    /// The textual representation used when written to an output stream, which includes whether the result was a\n    /// success or failure.\n    internal var description: String {\n        switch self {\n        case .success:\n            return \"SUCCESS\"\n        case .failure:\n            return \"FAILURE\"\n        }\n    }\n}\n\n// MARK: - CustomDebugStringConvertible\n\nextension CLDNResult: CustomDebugStringConvertible {\n    /// The debug textual representation used when written to an output stream, which includes whether the result was a\n    /// success or failure in addition to the value or error.\n    internal var debugDescription: String {\n        switch self {\n        case .success(let value):\n            return \"SUCCESS: \\(value)\"\n        case .failure(let error):\n            return \"FAILURE: \\(error)\"\n        }\n    }\n}\n\n// MARK: - Functional APIs\n\nextension CLDNResult {\n    /// Creates a `CLDNResult` instance from the result of a closure.\n    ///\n    /// A failure result is created when the closure throws, and a success result is created when the closure\n    /// succeeds without throwing an error.\n    ///\n    ///     func someString() throws -> String { ... }\n    ///\n    ///     let result = CLDNResult(value: {\n    ///         return try someString()\n    ///     })\n    ///\n    ///     // The type of result is CLDNResult<String>\n    ///\n    /// The trailing closure syntax is also supported:\n    ///\n    ///     let result = CLDNResult { try someString() }\n    ///\n    /// - parameter value: The closure to execute and create the result for.\n    internal init(value: () throws -> Value) {\n        do {\n            self = try .success(value())\n        } catch {\n            self = .failure(error)\n        }\n    }\n\n    /// Returns the success value, or throws the failure error.\n    ///\n    ///     let possibleString: Result<String> = .success(\"success\")\n    ///     try print(possibleString.unwrap())\n    ///     // Prints \"success\"\n    ///\n    ///     let noString: CLDNResult<String> = .failure(error)\n    ///     try print(noString.unwrap())\n    ///     // Throws error\n    internal func unwrap() throws -> Value {\n        switch self {\n        case .success(let value):\n            return value\n        case .failure(let error):\n            throw error\n        }\n    }\n\n    /// Evaluates the specified closure when the `CLDNResult` is a success, passing the unwrapped value as a parameter.\n    ///\n    /// Use the `map` method with a closure that does not throw. For example:\n    ///\n    ///     let possibleData: CLDNResult<Data> = .success(Data())\n    ///     let possibleInt = possibleData.map { $0.count }\n    ///     try print(possibleInt.unwrap())\n    ///     // Prints \"0\"\n    ///\n    ///     let noData: CLDNResult<Data> = .failure(error)\n    ///     let noInt = noData.map { $0.count }\n    ///     try print(noInt.unwrap())\n    ///     // Throws error\n    ///\n    /// - parameter transform: A closure that takes the success value of the `CLDNResult` instance.\n    ///\n    /// - returns: A `CLDNResult` containing the result of the given closure. If this instance is a failure, returns the\n    ///            same failure.\n    internal func map<T>(_ transform: (Value) -> T) -> CLDNResult<T> {\n        switch self {\n        case .success(let value):\n            return .success(transform(value))\n        case .failure(let error):\n            return .failure(error)\n        }\n    }\n\n    /// Evaluates the specified closure when the `CLDNResult` is a success, passing the unwrapped value as a parameter.\n    ///\n    /// Use the `flatMap` method with a closure that may throw an error. For example:\n    ///\n    ///     let possibleData: CLDNResult<Data> = .success(Data(...))\n    ///     let possibleObject = possibleData.flatMap {\n    ///         try JSONSerialization.jsonObject(with: $0)\n    ///     }\n    ///\n    /// - parameter transform: A closure that takes the success value of the instance.\n    ///\n    /// - returns: A `CLDNResult` containing the result of the given closure. If this instance is a failure, returns the\n    ///            same failure.\n    internal func flatMap<T>(_ transform: (Value) throws -> T) -> CLDNResult<T> {\n        switch self {\n        case .success(let value):\n            do {\n                return try .success(transform(value))\n            } catch {\n                return .failure(error)\n            }\n        case .failure(let error):\n            return .failure(error)\n        }\n    }\n\n    /// Evaluates the specified closure when the `CLDNResult` is a failure, passing the unwrapped error as a parameter.\n    ///\n    /// Use the `mapError` function with a closure that does not throw. For example:\n    ///\n    ///     let possibleData: CLDNResult<Data> = .failure(someError)\n    ///     let withMyError: CLDNResult<Data> = possibleData.mapError { MyError.error($0) }\n    ///\n    /// - Parameter transform: A closure that takes the error of the instance.\n    /// - Returns: A `CLDNResult` instance containing the result of the transform. If this instance is a success, returns\n    ///            the same instance.\n    internal func mapError<T: Error>(_ transform: (Error) -> T) -> CLDNResult {\n        switch self {\n        case .failure(let error):\n            return .failure(transform(error))\n        case .success:\n            return self\n        }\n    }\n\n    /// Evaluates the specified closure when the `CLDNResult` is a failure, passing the unwrapped error as a parameter.\n    ///\n    /// Use the `flatMapError` function with a closure that may throw an error. For example:\n    ///\n    ///     let possibleData: CLDNResult<Data> = .success(Data(...))\n    ///     let possibleObject = possibleData.flatMapError {\n    ///         try someFailableFunction(taking: $0)\n    ///     }\n    ///\n    /// - Parameter transform: A throwing closure that takes the error of the instance.\n    ///\n    /// - Returns: A `CLDNResult` instance containing the result of the transform. If this instance is a success, returns\n    ///            the same instance.\n    internal func flatMapError<T: Error>(_ transform: (Error) throws -> T) -> CLDNResult {\n        switch self {\n        case .failure(let error):\n            do {\n                return try .failure(transform(error))\n            } catch {\n                return .failure(error)\n            }\n        case .success:\n            return self\n        }\n    }\n\n    /// Evaluates the specified closure when the `CLDNResult` is a success, passing the unwrapped value as a parameter.\n    ///\n    /// Use the `withValue` function to evaluate the passed closure without modifying the `CLDNResult` instance.\n    ///\n    /// - Parameter closure: A closure that takes the success value of this instance.\n    /// - Returns: This `CLDNResult` instance, unmodified.\n    @discardableResult\n    internal func withValue(_ closure: (Value) throws -> Void) rethrows -> CLDNResult {\n        if case let .success(value) = self { try closure(value) }\n\n        return self\n    }\n\n    /// Evaluates the specified closure when the `CLDNResult` is a failure, passing the unwrapped error as a parameter.\n    ///\n    /// Use the `withError` function to evaluate the passed closure without modifying the `CLDNResult` instance.\n    ///\n    /// - Parameter closure: A closure that takes the success value of this instance.\n    /// - Returns: This `CLDNResult` instance, unmodified.\n    @discardableResult\n    internal func withError(_ closure: (Error) throws -> Void) rethrows -> CLDNResult {\n        if case let .failure(error) = self { try closure(error) }\n\n        return self\n    }\n\n    /// Evaluates the specified closure when the `CLDNResult` is a success.\n    ///\n    /// Use the `ifSuccess` function to evaluate the passed closure without modifying the `CLDNResult` instance.\n    ///\n    /// - Parameter closure: A `Void` closure.\n    /// - Returns: This `CLDNResult` instance, unmodified.\n    @discardableResult\n    internal func ifSuccess(_ closure: () throws -> Void) rethrows -> CLDNResult {\n        if isSuccess { try closure() }\n\n        return self\n    }\n\n    /// Evaluates the specified closure when the `CLDNResult` is a failure.\n    ///\n    /// Use the `ifFailure` function to evaluate the passed closure without modifying the `CLDNResult` instance.\n    ///\n    /// - Parameter closure: A `Void` closure.\n    /// - Returns: This `CLDNResult` instance, unmodified.\n    @discardableResult\n    internal func ifFailure(_ closure: () throws -> Void) rethrows -> CLDNResult {\n        if isFailure { try closure() }\n\n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNSessionDelegate.swift",
    "content": "//\n//  CLDNSessionDelegate.swift\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\nimport Foundation\n\n/// Responsible for handling all delegate callbacks for the underlying session.\ninternal class CLDNSessionDelegate: NSObject {\n\n    // MARK: URLSessionDelegate Overrides\n\n    /// Overrides default behavior for URLSessionDelegate method `urlSession(_:didBecomeInvalidWithError:)`.\n    internal var sessionDidBecomeInvalidWithError: ((URLSession, Error?) -> Void)?\n\n    /// Overrides default behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)`.\n    internal var sessionDidReceiveChallenge: ((URLSession, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?\n\n    /// Overrides all behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)` and requires the caller to call the `completionHandler`.\n    internal var sessionDidReceiveChallengeWithCompletion: ((URLSession, URLAuthenticationChallenge, @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void)?\n\n    /// Overrides default behavior for URLSessionDelegate method `urlSessionDidFinishEvents(forBackgroundURLSession:)`.\n    internal var sessionDidFinishEventsForBackgroundURLSession: ((URLSession) -> Void)?\n\n    // MARK: URLSessionTaskDelegate Overrides\n\n    /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)`.\n    internal var taskWillPerformHTTPRedirection: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest) -> URLRequest?)?\n\n    /// Overrides all behavior for URLSessionTaskDelegate method `urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)` and\n    /// requires the caller to call the `completionHandler`.\n    internal var taskWillPerformHTTPRedirectionWithCompletion: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest, @escaping (URLRequest?) -> Void) -> Void)?\n\n    /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:didReceive:completionHandler:)`.\n    internal var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?\n\n    /// Overrides all behavior for URLSessionTaskDelegate method `urlSession(_:task:didReceive:completionHandler:)` and\n    /// requires the caller to call the `completionHandler`.\n    internal var taskDidReceiveChallengeWithCompletion: ((URLSession, URLSessionTask, URLAuthenticationChallenge, @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void)?\n\n    /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:needNewBodyStream:)`.\n    internal var taskNeedNewBodyStream: ((URLSession, URLSessionTask) -> InputStream?)?\n\n    /// Overrides all behavior for URLSessionTaskDelegate method `urlSession(_:task:needNewBodyStream:)` and\n    /// requires the caller to call the `completionHandler`.\n    internal var taskNeedNewBodyStreamWithCompletion: ((URLSession, URLSessionTask, @escaping (InputStream?) -> Void) -> Void)?\n\n    /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)`.\n    internal var taskDidSendBodyData: ((URLSession, URLSessionTask, Int64, Int64, Int64) -> Void)?\n\n    /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:didCompleteWithError:)`.\n    internal var taskDidComplete: ((URLSession, URLSessionTask, Error?) -> Void)?\n\n    // MARK: URLSessionDataDelegate Overrides\n\n    /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didReceive:completionHandler:)`.\n    internal var dataTaskDidReceiveResponse: ((URLSession, URLSessionDataTask, URLResponse) -> URLSession.ResponseDisposition)?\n\n    /// Overrides all behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didReceive:completionHandler:)` and\n    /// requires caller to call the `completionHandler`.\n    internal var dataTaskDidReceiveResponseWithCompletion: ((URLSession, URLSessionDataTask, URLResponse, @escaping (URLSession.ResponseDisposition) -> Void) -> Void)?\n\n    /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didBecome:)`.\n    internal var dataTaskDidBecomeDownloadTask: ((URLSession, URLSessionDataTask, URLSessionDownloadTask) -> Void)?\n\n    /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didReceive:)`.\n    internal var dataTaskDidReceiveData: ((URLSession, URLSessionDataTask, Data) -> Void)?\n\n    /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:willCacheResponse:completionHandler:)`.\n    internal var dataTaskWillCacheResponse: ((URLSession, URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)?\n\n    /// Overrides all behavior for URLSessionDataDelegate method `urlSession(_:dataTask:willCacheResponse:completionHandler:)` and\n    /// requires caller to call the `completionHandler`.\n    internal var dataTaskWillCacheResponseWithCompletion: ((URLSession, URLSessionDataTask, CachedURLResponse, @escaping (CachedURLResponse?) -> Void) -> Void)?\n\n    // MARK: URLSessionDownloadDelegate Overrides\n\n    /// Overrides default behavior for URLSessionDownloadDelegate method `urlSession(_:downloadTask:didFinishDownloadingTo:)`.\n    internal var downloadTaskDidFinishDownloadingToURL: ((URLSession, URLSessionDownloadTask, URL) -> Void)?\n\n    /// Overrides default behavior for URLSessionDownloadDelegate method `urlSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)`.\n    internal var downloadTaskDidWriteData: ((URLSession, URLSessionDownloadTask, Int64, Int64, Int64) -> Void)?\n\n    /// Overrides default behavior for URLSessionDownloadDelegate method `urlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:)`.\n    internal var downloadTaskDidResumeAtOffset: ((URLSession, URLSessionDownloadTask, Int64, Int64) -> Void)?\n\n    // MARK: URLSessionStreamDelegate Overrides\n\n    // MARK: Properties\n\n    var retrier: CLDNRequestRetrier?\n    weak var sessionManager: CLDNSessionManager?\n\n    var requests: [Int: CLDNRequest] = [:]\n    private let lock = NSLock()\n\n    /// Access the task delegate for the specified task in a thread-safe manner.\n    internal subscript(task: URLSessionTask) -> CLDNRequest? {\n        get {\n            lock.lock() ; defer { lock.unlock() }\n            return requests[task.taskIdentifier]\n        }\n        set {\n            lock.lock() ; defer { lock.unlock() }\n            requests[task.taskIdentifier] = newValue\n        }\n    }\n\n    // MARK: Lifecycle\n\n    /// Initializes the `CLDNSessionDelegate` instance.\n    ///\n    /// - returns: The new `CLDNSessionDelegate` instance.\n    internal override init() {\n        super.init()\n    }\n\n    // MARK: NSObject Overrides\n\n    /// Returns a `Bool` indicating whether the `CLDNSessionDelegate` implements or inherits a method that can respond\n    /// to a specified message.\n    ///\n    /// - parameter selector: A selector that identifies a message.\n    ///\n    /// - returns: `true` if the receiver implements or inherits a method that can respond to selector, otherwise `false`.\n    internal override func responds(to selector: Selector) -> Bool {\n        #if !os(macOS)\n            if selector == #selector(URLSessionDelegate.urlSessionDidFinishEvents(forBackgroundURLSession:)) {\n                return sessionDidFinishEventsForBackgroundURLSession != nil\n            }\n        #endif\n\n        switch selector {\n        case #selector(URLSessionDelegate.urlSession(_:didBecomeInvalidWithError:)):\n            return sessionDidBecomeInvalidWithError != nil\n        case #selector(URLSessionDelegate.urlSession(_:didReceive:completionHandler:)):\n            return (sessionDidReceiveChallenge != nil  || sessionDidReceiveChallengeWithCompletion != nil)\n        case #selector(URLSessionTaskDelegate.urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)):\n            return (taskWillPerformHTTPRedirection != nil || taskWillPerformHTTPRedirectionWithCompletion != nil)\n        case #selector(URLSessionDataDelegate.urlSession(_:dataTask:didReceive:completionHandler:)):\n            return (dataTaskDidReceiveResponse != nil || dataTaskDidReceiveResponseWithCompletion != nil)\n        default:\n            return type(of: self).instancesRespond(to: selector)\n        }\n    }\n}\n\n// MARK: - URLSessionDelegate\n\nextension CLDNSessionDelegate: URLSessionDelegate {\n    /// Tells the delegate that the session has been invalidated.\n    ///\n    /// - parameter session: The session object that was invalidated.\n    /// - parameter error:   The error that caused invalidation, or nil if the invalidation was explicit.\n    internal func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {\n        sessionDidBecomeInvalidWithError?(session, error)\n    }\n\n    /// Requests credentials from the delegate in response to a session-level authentication request from the\n    /// remote server.\n    ///\n    /// - parameter session:           The session containing the task that requested authentication.\n    /// - parameter challenge:         An object that contains the request for authentication.\n    /// - parameter completionHandler: A handler that your delegate method must call providing the disposition\n    ///                                and credential.\n    internal func urlSession(\n        _ session: URLSession,\n        didReceive challenge: URLAuthenticationChallenge,\n        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)\n    {\n        guard sessionDidReceiveChallengeWithCompletion == nil else {\n            sessionDidReceiveChallengeWithCompletion?(session, challenge, completionHandler)\n            return\n        }\n\n        var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling\n        var credential: URLCredential?\n\n        if let sessionDidReceiveChallenge = sessionDidReceiveChallenge {\n            (disposition, credential) = sessionDidReceiveChallenge(session, challenge)\n        }\n\n        completionHandler(disposition, credential)\n    }\n\n#if !os(macOS)\n\n    /// Tells the delegate that all messages enqueued for a session have been delivered.\n    ///\n    /// - parameter session: The session that no longer has any outstanding requests.\n    internal func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {\n        sessionDidFinishEventsForBackgroundURLSession?(session)\n    }\n\n#endif\n}\n\n// MARK: - URLSessionTaskDelegate\n\nextension CLDNSessionDelegate: URLSessionTaskDelegate {\n    /// Tells the delegate that the remote server requested an HTTP redirect.\n    ///\n    /// - parameter session:           The session containing the task whose request resulted in a redirect.\n    /// - parameter task:              The task whose request resulted in a redirect.\n    /// - parameter response:          An object containing the server’s response to the original request.\n    /// - parameter request:           A URL request object filled out with the new location.\n    /// - parameter completionHandler: A closure that your handler should call with either the value of the request\n    ///                                parameter, a modified URL request object, or NULL to refuse the redirect and\n    ///                                return the body of the redirect response.\n    internal func urlSession(\n        _ session: URLSession,\n        task: URLSessionTask,\n        willPerformHTTPRedirection response: HTTPURLResponse,\n        newRequest request: URLRequest,\n        completionHandler: @escaping (URLRequest?) -> Void)\n    {\n        guard taskWillPerformHTTPRedirectionWithCompletion == nil else {\n            taskWillPerformHTTPRedirectionWithCompletion?(session, task, response, request, completionHandler)\n            return\n        }\n\n        var redirectRequest: URLRequest? = request\n\n        if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection {\n            redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request)\n        }\n\n        completionHandler(redirectRequest)\n    }\n\n    /// Requests credentials from the delegate in response to an authentication request from the remote server.\n    ///\n    /// - parameter session:           The session containing the task whose request requires authentication.\n    /// - parameter task:              The task whose request requires authentication.\n    /// - parameter challenge:         An object that contains the request for authentication.\n    /// - parameter completionHandler: A handler that your delegate method must call providing the disposition\n    ///                                and credential.\n    internal func urlSession(\n        _ session: URLSession,\n        task: URLSessionTask,\n        didReceive challenge: URLAuthenticationChallenge,\n        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)\n    {\n        guard taskDidReceiveChallengeWithCompletion == nil else {\n            taskDidReceiveChallengeWithCompletion?(session, task, challenge, completionHandler)\n            return\n        }\n\n        if let taskDidReceiveChallenge = taskDidReceiveChallenge {\n            let result = taskDidReceiveChallenge(session, task, challenge)\n            completionHandler(result.0, result.1)\n        } else if let delegate = self[task]?.delegate {\n            delegate.urlSession(\n                session,\n                task: task,\n                didReceive: challenge,\n                completionHandler: completionHandler\n            )\n        } else {\n            urlSession(session, didReceive: challenge, completionHandler: completionHandler)\n        }\n    }\n\n    /// Tells the delegate when a task requires a new request body stream to send to the remote server.\n    ///\n    /// - parameter session:           The session containing the task that needs a new body stream.\n    /// - parameter task:              The task that needs a new body stream.\n    /// - parameter completionHandler: A completion handler that your delegate method should call with the new body stream.\n    internal func urlSession(\n        _ session: URLSession,\n        task: URLSessionTask,\n        needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)\n    {\n        guard taskNeedNewBodyStreamWithCompletion == nil else {\n            taskNeedNewBodyStreamWithCompletion?(session, task, completionHandler)\n            return\n        }\n\n        if let taskNeedNewBodyStream = taskNeedNewBodyStream {\n            completionHandler(taskNeedNewBodyStream(session, task))\n        } else if let delegate = self[task]?.delegate {\n            delegate.urlSession(session, task: task, needNewBodyStream: completionHandler)\n        }\n    }\n\n    /// Periodically informs the delegate of the progress of sending body content to the server.\n    ///\n    /// - parameter session:                  The session containing the data task.\n    /// - parameter task:                     The data task.\n    /// - parameter bytesSent:                The number of bytes sent since the last time this delegate method was called.\n    /// - parameter totalBytesSent:           The total number of bytes sent so far.\n    /// - parameter totalBytesExpectedToSend: The expected length of the body data.\n    internal func urlSession(\n        _ session: URLSession,\n        task: URLSessionTask,\n        didSendBodyData bytesSent: Int64,\n        totalBytesSent: Int64,\n        totalBytesExpectedToSend: Int64)\n    {\n        if let taskDidSendBodyData = taskDidSendBodyData {\n            taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend)\n        } else if let delegate = self[task]?.delegate as? CLDNUploadTaskDelegate {\n            delegate.URLSession(\n                session,\n                task: task,\n                didSendBodyData: bytesSent,\n                totalBytesSent: totalBytesSent,\n                totalBytesExpectedToSend: totalBytesExpectedToSend\n            )\n        }\n    }\n\n#if !os(watchOS)\n\n    /// Tells the delegate that the session finished collecting metrics for the task.\n    ///\n    /// - parameter session: The session collecting the metrics.\n    /// - parameter task:    The task whose metrics have been collected.\n    /// - parameter metrics: The collected metrics.\n    @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)\n    @objc(URLSession:task:didFinishCollectingMetrics:)\n    internal func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {\n        self[task]?.delegate.metrics = metrics\n    }\n\n#endif\n\n    /// Tells the delegate that the task finished transferring data.\n    ///\n    /// - parameter session: The session containing the task whose request finished transferring data.\n    /// - parameter task:    The task whose request finished transferring data.\n    /// - parameter error:   If an error occurred, an error object indicating how the transfer failed, otherwise nil.\n    internal func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {\n        /// Executed after it is determined that the request is not going to be retried\n        let completeTask: (URLSession, URLSessionTask, Error?) -> Void = { [weak self] session, task, error in\n            guard let strongSelf = self else { return }\n\n            strongSelf.taskDidComplete?(session, task, error)\n\n            strongSelf[task]?.delegate.urlSession(session, task: task, didCompleteWithError: error)\n\n            strongSelf[task] = nil\n        }\n\n        guard let request = self[task], let sessionManager = sessionManager else {\n            completeTask(session, task, error)\n            return\n        }\n\n        // Run all validations on the request before checking if an error occurred\n        request.validations.forEach { $0() }\n\n        // Determine whether an error has occurred\n        var error: Error? = error\n\n        if request.delegate.error != nil {\n            error = request.delegate.error\n        }\n        \n        /// If an error occurred and the retrier is set, asynchronously ask the retrier if the request\n        /// should be retried. Otherwise, complete the task by notifying the task delegate.\n        if let retrier = retrier, let error = error {\n            retrier.CLDN_Should(sessionManager, retry: request, with: error) { [weak self] shouldRetry, timeDelay in\n                guard shouldRetry else { completeTask(session, task, error) ; return }\n\n                DispatchQueue.CLDNUtility.CLDN_after(timeDelay) { [weak self] in\n                    guard let strongSelf = self else { return }\n\n                    let retrySucceeded = strongSelf.sessionManager?.retry(request) ?? false\n\n                    if retrySucceeded, let task = request.task {\n                        strongSelf[task] = request\n                        return\n                    } else {\n                        completeTask(session, task, error)\n                    }\n                }\n            }\n        } else {\n            completeTask(session, task, error)\n        }\n    }\n}\n\n// MARK: - URLSessionDataDelegate\n\nextension CLDNSessionDelegate: URLSessionDataDelegate {\n    /// Tells the delegate that the data task received the initial reply (headers) from the server.\n    ///\n    /// - parameter session:           The session containing the data task that received an initial reply.\n    /// - parameter dataTask:          The data task that received an initial reply.\n    /// - parameter response:          A URL response object populated with headers.\n    /// - parameter completionHandler: A completion handler that your code calls to continue the transfer, passing a\n    ///                                constant to indicate whether the transfer should continue as a data task or\n    ///                                should become a download task.\n    internal func urlSession(\n        _ session: URLSession,\n        dataTask: URLSessionDataTask,\n        didReceive response: URLResponse,\n        completionHandler: @escaping (URLSession.ResponseDisposition) -> Void)\n    {\n        guard dataTaskDidReceiveResponseWithCompletion == nil else {\n            dataTaskDidReceiveResponseWithCompletion?(session, dataTask, response, completionHandler)\n            return\n        }\n\n        var disposition: URLSession.ResponseDisposition = .allow\n\n        if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse {\n            disposition = dataTaskDidReceiveResponse(session, dataTask, response)\n        }\n\n        completionHandler(disposition)\n    }\n\n    /// Tells the delegate that the data task has received some of the expected data.\n    ///\n    /// - parameter session:  The session containing the data task that provided data.\n    /// - parameter dataTask: The data task that provided data.\n    /// - parameter data:     A data object containing the transferred data.\n    internal func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {\n        if let dataTaskDidReceiveData = dataTaskDidReceiveData {\n            dataTaskDidReceiveData(session, dataTask, data)\n        } else if let delegate = self[dataTask]?.delegate as? CLDNDataTaskDelegate {\n            delegate.urlSession(session, dataTask: dataTask, didReceive: data)\n        }\n    }\n\n    /// Asks the delegate whether the data (or upload) task should store the response in the cache.\n    ///\n    /// - parameter session:           The session containing the data (or upload) task.\n    /// - parameter dataTask:          The data (or upload) task.\n    /// - parameter proposedResponse:  The default caching behavior. This behavior is determined based on the current\n    ///                                caching policy and the values of certain received headers, such as the Pragma\n    ///                                and Cache-Control headers.\n    /// - parameter completionHandler: A block that your handler must call, providing either the original proposed\n    ///                                response, a modified version of that response, or NULL to prevent caching the\n    ///                                response. If your delegate implements this method, it must call this completion\n    ///                                handler; otherwise, your app leaks memory.\n    internal func urlSession(\n        _ session: URLSession,\n        dataTask: URLSessionDataTask,\n        willCacheResponse proposedResponse: CachedURLResponse,\n        completionHandler: @escaping (CachedURLResponse?) -> Void)\n    {\n        guard dataTaskWillCacheResponseWithCompletion == nil else {\n            dataTaskWillCacheResponseWithCompletion?(session, dataTask, proposedResponse, completionHandler)\n            return\n        }\n\n        if let dataTaskWillCacheResponse = dataTaskWillCacheResponse {\n            completionHandler(dataTaskWillCacheResponse(session, dataTask, proposedResponse))\n        } else if let delegate = self[dataTask]?.delegate as? CLDNDataTaskDelegate {\n            delegate.urlSession(\n                session,\n                dataTask: dataTask,\n                willCacheResponse: proposedResponse,\n                completionHandler: completionHandler\n            )\n        } else {\n            completionHandler(proposedResponse)\n        }\n    }\n}\n\n// MARK: - URLSessionDownloadDelegate\n\nextension CLDNSessionDelegate: URLSessionDownloadDelegate {\n    /// Tells the delegate that a download task has finished downloading.\n    ///\n    /// - parameter session:      The session containing the download task that finished.\n    /// - parameter downloadTask: The download task that finished.\n    /// - parameter location:     A file URL for the temporary file. Because the file is temporary, you must either\n    ///                           internal the file for reading or move it to a permanent location in your app’s sandbox\n    ///                           container directory before returning from this delegate method.\n    internal func urlSession(\n        _ session: URLSession,\n        downloadTask: URLSessionDownloadTask,\n        didFinishDownloadingTo location: URL)\n    {\n        if let downloadTaskDidFinishDownloadingToURL = downloadTaskDidFinishDownloadingToURL {\n            downloadTaskDidFinishDownloadingToURL(session, downloadTask, location)\n        }\n    }\n\n    /// Periodically informs the delegate about the download’s progress.\n    ///\n    /// - parameter session:                   The session containing the download task.\n    /// - parameter downloadTask:              The download task.\n    /// - parameter bytesWritten:              The number of bytes transferred since the last time this delegate\n    ///                                        method was called.\n    /// - parameter totalBytesWritten:         The total number of bytes transferred so far.\n    /// - parameter totalBytesExpectedToWrite: The expected length of the file, as provided by the Content-Length\n    ///                                        header. If this header was not provided, the value is\n    ///                                        `NSURLSessionTransferSizeUnknown`.\n    internal func urlSession(\n        _ session: URLSession,\n        downloadTask: URLSessionDownloadTask,\n        didWriteData bytesWritten: Int64,\n        totalBytesWritten: Int64,\n        totalBytesExpectedToWrite: Int64)\n    {\n        if let downloadTaskDidWriteData = downloadTaskDidWriteData {\n            downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)\n        }\n    }\n\n    /// Tells the delegate that the download task has resumed downloading.\n    ///\n    /// - parameter session:            The session containing the download task that finished.\n    /// - parameter downloadTask:       The download task that resumed. See explanation in the discussion.\n    /// - parameter fileOffset:         If the file's cache policy or last modified date prevents reuse of the\n    ///                                 existing content, then this value is zero. Otherwise, this value is an\n    ///                                 integer representing the number of bytes on disk that do not need to be\n    ///                                 retrieved again.\n    /// - parameter expectedTotalBytes: The expected length of the file, as provided by the Content-Length header.\n    ///                                 If this header was not provided, the value is NSURLSessionTransferSizeUnknown.\n    internal func urlSession(\n        _ session: URLSession,\n        downloadTask: URLSessionDownloadTask,\n        didResumeAtOffset fileOffset: Int64,\n        expectedTotalBytes: Int64)\n    {\n        if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset {\n            downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes)\n        }\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNSessionManager.swift",
    "content": "//\n//  CLDNSessionManager.swift\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\nimport Foundation\n\n/// Responsible for creating and managing `CLDNRequest` objects, as well as their underlying `NSURLSession`.\ninternal class CLDNSessionManager {\n\n    // MARK: - Helper Types\n\n    /// Defines whether the `CLDNMultipartFormData` encoding was successful and contains result of the encoding as\n    /// associated values.\n    ///\n    /// - Success: Represents a successful `CLDNMultipartFormData` encoding and contains the new `CLDNUploadRequest` along with\n    ///            streaming information.\n    /// - Failure: Used to represent a failure in the `CLDNMultipartFormData` encoding and also contains the encoding\n    ///            error.\n    internal enum MultipartFormDataEncodingResult {\n        case success(request: CLDNUploadRequest, streamingFromDisk: Bool, streamFileURL: URL?)\n        case failure(Error)\n    }\n\n    // MARK: - Properties\n\n    /// A default instance of `SessionManager`, used by top-level Cloudinary request methods, and suitable for use\n    /// directly for any ad hoc requests.\n    internal static let `default`: CLDNSessionManager = {\n        let configuration = URLSessionConfiguration.default\n        configuration.httpAdditionalHeaders = CLDNSessionManager.defaultHTTPHeaders\n\n        return CLDNSessionManager(configuration: configuration)\n    }()\n\n    /// Creates default values for the \"Accept-Encoding\", \"Accept-Language\" and \"User-Agent\" headers.\n    internal static let defaultHTTPHeaders: CLDNHTTPHeaders = {\n        // Accept-Encoding HTTP Header; see https://tools.ietf.org/html/rfc7230#section-4.2.3\n        let acceptEncoding: String = \"gzip;q=1.0, compress;q=0.5\"\n\n        // Accept-Language HTTP Header; see https://tools.ietf.org/html/rfc7231#section-5.3.5\n        let acceptLanguage = Locale.preferredLanguages.prefix(6).enumerated().map { index, languageCode in\n            let quality = 1.0 - (Double(index) * 0.1)\n            return \"\\(languageCode);q=\\(quality)\"\n        }.joined(separator: \", \")\n\n        // User-Agent Header; see https://tools.ietf.org/html/rfc7231#section-5.5.3\n        // Example: `iOS Example/1.0 (org.cloudinary.iOS-Example; build:1; iOS 10.0.0) cloudinary/4.0.0`\n        let userAgent: String = {\n            if let info = Bundle.main.infoDictionary {\n                let executable = info[kCFBundleExecutableKey as String] as? String ?? \"Unknown\"\n                let bundle = info[kCFBundleIdentifierKey as String] as? String ?? \"Unknown\"\n                let appVersion = info[\"CFBundleShortVersionString\"] as? String ?? \"Unknown\"\n                let appBuild = info[kCFBundleVersionKey as String] as? String ?? \"Unknown\"\n\n                let osNameVersion: String = {\n                    let version = ProcessInfo.processInfo.operatingSystemVersion\n                    let versionString = \"\\(version.majorVersion).\\(version.minorVersion).\\(version.patchVersion)\"\n\n                    let osName: String = {\n                        #if os(iOS)\n                            return \"iOS\"\n                        #elseif os(watchOS)\n                            return \"watchOS\"\n                        #elseif os(tvOS)\n                            return \"tvOS\"\n                        #elseif os(macOS)\n                            return \"OS X\"\n                        #elseif os(Linux)\n                            return \"Linux\"\n                        #else\n                            return \"Unknown\"\n                        #endif\n                    }()\n\n                    return \"\\(osName) \\(versionString)\"\n                }()\n\n                let cloudinaryVersion: String = {\n                    guard\n                        let afInfo = Bundle(for: CLDNSessionManager.self).infoDictionary,\n                        let build = afInfo[\"CFBundleShortVersionString\"]\n                    else { return \"Unknown\" }\n\n                    return \"Cloudinary/\\(build)\"\n                }()\n\n                return \"\\(executable)/\\(appVersion) (\\(bundle); build:\\(appBuild); \\(osNameVersion)) \\(cloudinaryVersion)\"\n            }\n\n            return \"Cloudinary\"\n        }()\n\n        return [\n            \"Accept-Encoding\": acceptEncoding,\n            \"Accept-Language\": acceptLanguage,\n            \"User-Agent\": userAgent\n        ]\n    }()\n\n    /// Default memory threshold used when encoding `MultipartFormData` in bytes.\n    internal static let multipartFormDataEncodingMemoryThreshold: UInt64 = 10_000_000\n\n    /// The underlying session.\n    internal let session: URLSession\n\n    /// The session delegate handling all the task and session delegate callbacks.\n    internal let delegate: CLDNSessionDelegate\n\n    /// Whether to start requests immediately after being constructed. `true` by default.\n    internal var startRequestsImmediately: Bool = true\n\n    /// The request adapter called each time a new request is created.\n    internal var adapter: CLDNRequestAdapter?\n\n    /// The request retrier called each time a request encounters an error to determine whether to retry the request.\n    internal var retrier: CLDNRequestRetrier? {\n        get { return delegate.retrier }\n        set { delegate.retrier = newValue }\n    }\n\n    /// The background completion handler closure provided by the UIApplicationDelegate\n    /// `application:handleEventsForBackgroundURLSession:completionHandler:` method. By setting the background\n    /// completion handler, the SessionDelegate `sessionDidFinishEventsForBackgroundURLSession` closure implementation\n    /// will automatically call the handler.\n    ///\n    /// If you need to handle your own events before the handler is called, then you need to override the\n    /// SessionDelegate `sessionDidFinishEventsForBackgroundURLSession` and manually call the handler when finished.\n    ///\n    /// `nil` by default.\n    internal var backgroundCompletionHandler: (() -> Void)?\n\n    let queue = DispatchQueue(label: \"com.cloudinary.session-manager.\" + UUID().uuidString)\n\n    // MARK: - Lifecycle\n\n    /// Creates an instance with the specified `configuration`, `delegate` and `serverTrustPolicyManager`.\n    ///\n    /// - parameter configuration:            The configuration used to construct the managed session.\n    ///                                       `URLSessionConfiguration.default` by default.\n    /// - parameter delegate:                 The delegate used when initializing the session. `CLDNSessionDelegate()` by\n    ///                                       default.\n    /// - parameter serverTrustPolicyManager: The server trust policy manager to use for evaluating all server trust\n    ///                                       challenges. `nil` by default.\n    ///\n    /// - returns: The new `CLDNSessionManager` instance.\n    internal init(\n        configuration: URLSessionConfiguration = URLSessionConfiguration.default,\n        delegate: CLDNSessionDelegate = CLDNSessionDelegate())\n    {\n        configuration.urlCredentialStorage = nil;\n        self.delegate = delegate\n        self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)\n\n        commonInit()\n    }\n\n    /// Creates an instance with the specified `session`, `delegate` and `serverTrustPolicyManager`.\n    ///\n    /// - parameter session:                  The URL session.\n    /// - parameter delegate:                 The delegate of the URL session. Must equal the URL session's delegate.\n    /// - parameter serverTrustPolicyManager: The server trust policy manager to use for evaluating all server trust\n    ///                                       challenges. `nil` by default.\n    ///\n    /// - returns: The new `CLDNSessionManager` instance if the URL session's delegate matches; `nil` otherwise.\n    internal init?(\n        session: URLSession,\n        delegate: CLDNSessionDelegate)\n    {\n        guard delegate === session.delegate else { return nil }\n\n        self.delegate = delegate\n        self.session = session\n\n        commonInit()\n    }\n\n    private func commonInit() {\n\n        delegate.sessionManager = self\n\n        delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in\n            guard let strongSelf = self else { return }\n            DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() }\n        }\n    }\n\n    deinit {\n        session.invalidateAndCancel()\n    }\n\n    // MARK: - Data Request\n\n    /// Creates a `CLDNDataRequest` to retrieve the contents of the specified `url`, `method`, `parameters`, `encoding`\n    /// and `headers`.\n    ///\n    /// - parameter url:        The URL.\n    /// - parameter method:     The HTTP method. `.get` by default.\n    /// - parameter parameters: The parameters. `nil` by default.\n    /// - parameter encoding:   The parameter encoding. `CLDNURLEncoding.default` by default.\n    /// - parameter headers:    The HTTP headers. `nil` by default.\n    ///\n    /// - returns: The created `CLDNDataRequest`.\n    @discardableResult\n    internal func request(\n        _ url: CLDNURLConvertible,\n        method: CLDNHTTPMethod = .get,\n        parameters: CLDNParameters? = nil,\n        encoding: CLDNParameterEncoding = CLDNURLEncoding.default,\n        headers: CLDNHTTPHeaders? = nil)\n        -> CLDNDataRequest\n    {\n        var originalRequest: URLRequest?\n\n        do {\n            var parameters = parameters\n            let timeoutParamater = parameters?.removeValue(forKey: CLDConfiguration.ConfigParam.Timeout.description)\n            \n            originalRequest = try URLRequest(url: url, method: method, headers: headers)\n            var encodedURLRequest = try encoding.CLDN_Encode(originalRequest!, with: parameters)\n            \n            if let timeout = timeoutParamater as? NSNumber {\n                encodedURLRequest.timeoutInterval = timeout.doubleValue\n            }\n            \n            return request(encodedURLRequest)\n        } catch {\n            return request(originalRequest, failedWith: error)\n        }\n    }\n\n    /// Creates a `CLDNDataRequest` to retrieve the contents of a URL based on the specified `urlRequest`.\n    ///\n    /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.\n    ///\n    /// - parameter urlRequest: The URL request.\n    ///\n    /// - returns: The created `CLDNDataRequest`.\n    @discardableResult\n    internal func request(_ urlRequest: CLDNURLRequestConvertible) -> CLDNDataRequest {\n        var originalRequest: URLRequest?\n\n        do {\n            originalRequest = try urlRequest.CLDN_AsURLRequest()\n            let originalTask = CLDNDataRequest.Requestable(urlRequest: originalRequest!)\n\n            let task = try originalTask.CLDN_Task(session: session, adapter: adapter, queue: queue)\n            let request = CLDNDataRequest(session: session, requestTask: .data(originalTask, task))\n\n            delegate[task] = request\n\n            if startRequestsImmediately { request.resume() }\n\n            return request\n        } catch {\n            return request(originalRequest, failedWith: error)\n        }\n    }\n\n    // MARK: Private - Request Implementation\n\n    private func request(_ urlRequest: URLRequest?, failedWith error: Error) -> CLDNDataRequest {\n        var requestTask: CLDNRequest.RequestTask = .data(nil, nil)\n\n        if let urlRequest = urlRequest {\n            let originalTask = CLDNDataRequest.Requestable(urlRequest: urlRequest)\n            requestTask = .data(originalTask, nil)\n        }\n\n        let underlyingError = error.underlyingAdaptError ?? error\n        let request = CLDNDataRequest(session: session, requestTask: requestTask, error: underlyingError)\n\n        if let retrier = retrier, error is AdaptError {\n            allowRetrier(retrier, toRetry: request, with: underlyingError)\n        } else {\n            if startRequestsImmediately { request.resume() }\n        }\n\n        return request\n    }\n\n    // MARK: - Upload Request\n\n    // MARK: File\n\n    /// Creates an `CLDNUploadRequest` from the specified `url`, `method` and `headers` for uploading the `file`.\n    ///\n    /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.\n    ///\n    /// - parameter file:    The file to upload.\n    /// - parameter url:     The URL.\n    /// - parameter method:  The HTTP method. `.post` by default.\n    /// - parameter headers: The HTTP headers. `nil` by default.\n    ///\n    /// - returns: The created `CLDNUploadRequest`.\n    @discardableResult\n    internal func upload(\n        _ fileURL: URL,\n        to url: CLDNURLConvertible,\n        method: CLDNHTTPMethod = .post,\n        headers: CLDNHTTPHeaders? = nil)\n        -> CLDNUploadRequest\n    {\n        do {\n            let urlRequest = try URLRequest(url: url, method: method, headers: headers)\n            return upload(fileURL, with: urlRequest)\n        } catch {\n            return upload(nil, failedWith: error)\n        }\n    }\n\n    /// Creates a `CLDNUploadRequest` from the specified `urlRequest` for uploading the `file`.\n    ///\n    /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.\n    ///\n    /// - parameter file:       The file to upload.\n    /// - parameter urlRequest: The URL request.\n    ///\n    /// - returns: The created `CLDNUploadRequest`.\n    @discardableResult\n    internal func upload(_ fileURL: URL, with urlRequest: CLDNURLRequestConvertible) -> CLDNUploadRequest {\n        do {\n            let urlRequest = try urlRequest.CLDN_AsURLRequest()\n            return upload(.file(fileURL, urlRequest))\n        } catch {\n            return upload(nil, failedWith: error)\n        }\n    }\n\n    // MARK: Data\n\n    /// Creates an `CLDNUploadRequest` from the specified `url`, `method` and `headers` for uploading the `data`.\n    ///\n    /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.\n    ///\n    /// - parameter data:    The data to upload.\n    /// - parameter url:     The URL.\n    /// - parameter method:  The HTTP method. `.post` by default.\n    /// - parameter headers: The HTTP headers. `nil` by default.\n    ///\n    /// - returns: The created `CLDNUploadRequest`.\n    @discardableResult\n    internal func upload(\n        _ data: Data,\n        to url: CLDNURLConvertible,\n        method: CLDNHTTPMethod = .post,\n        headers: CLDNHTTPHeaders? = nil)\n        -> CLDNUploadRequest\n    {\n        do {\n            let urlRequest = try URLRequest(url: url, method: method, headers: headers)\n            return upload(data, with: urlRequest)\n        } catch {\n            return upload(nil, failedWith: error)\n        }\n    }\n\n    /// Creates an `CLDNUploadRequest` from the specified `urlRequest` for uploading the `data`.\n    ///\n    /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.\n    ///\n    /// - parameter data:       The data to upload.\n    /// - parameter urlRequest: The URL request.\n    ///\n    /// - returns: The created `CLDNUploadRequest`.\n    @discardableResult\n    internal func upload(_ data: Data, with urlRequest: CLDNURLRequestConvertible) -> CLDNUploadRequest {\n        do {\n            let urlRequest = try urlRequest.CLDN_AsURLRequest()\n            return upload(.data(data, urlRequest))\n        } catch {\n            return upload(nil, failedWith: error)\n        }\n    }\n\n    // MARK: InputStream\n\n    /// Creates an `CLDNUploadRequest` from the specified `url`, `method` and `headers` for uploading the `stream`.\n    ///\n    /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.\n    ///\n    /// - parameter stream:  The stream to upload.\n    /// - parameter url:     The URL.\n    /// - parameter method:  The HTTP method. `.post` by default.\n    /// - parameter headers: The HTTP headers. `nil` by default.\n    ///\n    /// - returns: The created `CLDNUploadRequest`.\n    @discardableResult\n    internal func upload(\n        _ stream: InputStream,\n        to url: CLDNURLConvertible,\n        method: CLDNHTTPMethod = .post,\n        headers: CLDNHTTPHeaders? = nil)\n        -> CLDNUploadRequest\n    {\n        do {\n            let urlRequest = try URLRequest(url: url, method: method, headers: headers)\n            return upload(stream, with: urlRequest)\n        } catch {\n            return upload(nil, failedWith: error)\n        }\n    }\n\n    /// Creates an `CLDNUploadRequest` from the specified `urlRequest` for uploading the `stream`.\n    ///\n    /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.\n    ///\n    /// - parameter stream:     The stream to upload.\n    /// - parameter urlRequest: The URL request.\n    ///\n    /// - returns: The created `CLDNUploadRequest`.\n    @discardableResult\n    internal func upload(_ stream: InputStream, with urlRequest: CLDNURLRequestConvertible) -> CLDNUploadRequest {\n        do {\n            let urlRequest = try urlRequest.CLDN_AsURLRequest()\n            return upload(.stream(stream, urlRequest))\n        } catch {\n            return upload(nil, failedWith: error)\n        }\n    }\n\n    // MARK: CLDNMultipartFormData\n\n    /// Encodes `multipartFormData` using `encodingMemoryThreshold` and calls `encodingCompletion` with new\n    /// `CLDNUploadRequest` using the `url`, `method` and `headers`.\n    ///\n    /// It is important to understand the memory implications of uploading `CLDNMultipartFormData`. If the cummulative\n    /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most\n    /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to\n    /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory\n    /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be\n    /// used for larger payloads such as video content.\n    ///\n    /// The `encodingMemoryThreshold` parameter allows Cloudinary to automatically determine whether to encode in-memory\n    /// or stream from disk. If the content length of the `CLDNMultipartFormData` is below the `encodingMemoryThreshold`,\n    /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk\n    /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding\n    /// technique was used.\n    ///\n    /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.\n    ///\n    /// - parameter multipartFormData:       The closure used to append body parts to the `CLDNMultipartFormData`.\n    /// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes.\n    ///                                      `multipartFormDataEncodingMemoryThreshold` by default.\n    /// - parameter url:                     The URL.\n    /// - parameter method:                  The HTTP method. `.post` by default.\n    /// - parameter headers:                 The HTTP headers. `nil` by default.\n    /// - parameter encodingCompletion:      The closure called when the `CLDNMultipartFormData` encoding is complete.\n    internal func upload(\n        multipartFormData: @escaping (CLDNMultipartFormData) -> Void,\n        usingThreshold encodingMemoryThreshold: UInt64 = CLDNSessionManager.multipartFormDataEncodingMemoryThreshold,\n        to url: CLDNURLConvertible,\n        method: CLDNHTTPMethod = .post,\n        headers: CLDNHTTPHeaders? = nil,\n        queue: DispatchQueue? = nil,\n        timeout: NSNumber? = nil,\n        encodingCompletion: ((MultipartFormDataEncodingResult) -> Void)?)\n    {\n        do {\n            var urlRequest = try URLRequest(url: url, method: method, headers: headers)\n            if let timeout = timeout {\n                urlRequest.timeoutInterval = timeout.doubleValue\n            }\n            return upload(\n                multipartFormData: multipartFormData,\n                usingThreshold: encodingMemoryThreshold,\n                with: urlRequest,\n                queue: queue,\n                encodingCompletion: encodingCompletion\n            )\n        } catch {\n            (queue ?? DispatchQueue.main).async { encodingCompletion?(.failure(error)) }\n        }\n    }\n\n    /// Encodes `multipartFormData` using `encodingMemoryThreshold` and calls `encodingCompletion` with new\n    /// `CLDNUploadRequest` using the `urlRequest`.\n    ///\n    /// It is important to understand the memory implications of uploading `CLDNMultipartFormData`. If the cummulative\n    /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most\n    /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to\n    /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory\n    /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be\n    /// used for larger payloads such as video content.\n    ///\n    /// The `encodingMemoryThreshold` parameter allows Cloudinary to automatically determine whether to encode in-memory\n    /// or stream from disk. If the content length of the `CLDNMultipartFormData` is below the `encodingMemoryThreshold`,\n    /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk\n    /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding\n    /// technique was used.\n    ///\n    /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.\n    ///\n    /// - parameter multipartFormData:       The closure used to append body parts to the `CLDNMultipartFormData`.\n    /// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes.\n    ///                                      `multipartFormDataEncodingMemoryThreshold` by default.\n    /// - parameter urlRequest:              The URL request.\n    /// - parameter encodingCompletion:      The closure called when the `CLDNMultipartFormData` encoding is complete.\n    internal func upload(\n        multipartFormData: @escaping (CLDNMultipartFormData) -> Void,\n        usingThreshold encodingMemoryThreshold: UInt64 = CLDNSessionManager.multipartFormDataEncodingMemoryThreshold,\n        with urlRequest: CLDNURLRequestConvertible,\n        queue: DispatchQueue? = nil,\n        encodingCompletion: ((MultipartFormDataEncodingResult) -> Void)?)\n    {\n        DispatchQueue.global(qos: .utility).async {\n            let formData = CLDNMultipartFormData()\n            multipartFormData(formData)\n\n            var tempFileURL: URL?\n\n            do {\n                var urlRequestWithContentType = try urlRequest.CLDN_AsURLRequest()\n                urlRequestWithContentType.setValue(formData.contentType, forHTTPHeaderField: \"Content-Type\")\n\n                let isBackgroundSession = self.session.configuration.identifier != nil\n\n                if formData.contentLength < encodingMemoryThreshold && !isBackgroundSession {\n                    let data = try formData.encode()\n\n                    let encodingResult = MultipartFormDataEncodingResult.success(\n                        request: self.upload(data, with: urlRequestWithContentType),\n                        streamingFromDisk: false,\n                        streamFileURL: nil\n                    )\n\n                    (queue ?? DispatchQueue.main).async { encodingCompletion?(encodingResult) }\n                } else {\n                    let fileManager = FileManager.default\n                    let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory())\n                    let directoryURL = tempDirectoryURL.appendingPathComponent(\"org.cloudinary.manager/multipart.form.data\")\n                    let fileName = UUID().uuidString\n                    let fileURL = directoryURL.appendingPathComponent(fileName)\n\n                    tempFileURL = fileURL\n\n                    var directoryError: Error?\n\n                    // Create directory inside serial queue to ensure two threads don't do this in parallel\n                    self.queue.sync {\n                        do {\n                            try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)\n                        } catch {\n                            directoryError = error\n                        }\n                    }\n\n                    if let directoryError = directoryError { throw directoryError }\n\n                    try formData.writeEncodedData(to: fileURL)\n\n                    let upload = self.upload(fileURL, with: urlRequestWithContentType)\n\n                    // Cleanup the temp file once the upload is complete\n                    upload.delegate.queue.addOperation {\n                        do {\n                            try FileManager.default.removeItem(at: fileURL)\n                        } catch {\n                            // No-op\n                        }\n                    }\n\n                    (queue ?? DispatchQueue.main).async {\n                        let encodingResult = MultipartFormDataEncodingResult.success(\n                            request: upload,\n                            streamingFromDisk: true,\n                            streamFileURL: fileURL\n                        )\n\n                        encodingCompletion?(encodingResult)\n                    }\n                }\n            } catch {\n                // Cleanup the temp file in the event that the multipart form data encoding failed\n                if let tempFileURL = tempFileURL {\n                    do {\n                        try FileManager.default.removeItem(at: tempFileURL)\n                    } catch {\n                        // No-op\n                    }\n                }\n\n                (queue ?? DispatchQueue.main).async { encodingCompletion?(.failure(error)) }\n            }\n        }\n    }\n\n    // MARK: Private - Upload Implementation\n\n    private func upload(_ uploadable: CLDNUploadRequest.Uploadable) -> CLDNUploadRequest {\n        do {\n            let task = try uploadable.CLDN_Task(session: session, adapter: adapter, queue: queue)\n            let upload = CLDNUploadRequest(session: session, requestTask: .upload(uploadable, task))\n\n            if case let .stream(inputStream, _) = uploadable {\n                upload.delegate.taskNeedNewBodyStream = { _, _ in inputStream }\n            }\n\n            delegate[task] = upload\n\n            if startRequestsImmediately { upload.resume() }\n\n            return upload\n        } catch {\n            return upload(uploadable, failedWith: error)\n        }\n    }\n\n    private func upload(_ uploadable: CLDNUploadRequest.Uploadable?, failedWith error: Error) -> CLDNUploadRequest {\n        var uploadTask: CLDNRequest.RequestTask = .upload(nil, nil)\n\n        if let uploadable = uploadable {\n            uploadTask = .upload(uploadable, nil)\n        }\n\n        let underlyingError = error.underlyingAdaptError ?? error\n        let upload = CLDNUploadRequest(session: session, requestTask: uploadTask, error: underlyingError)\n\n        if let retrier = retrier, error is AdaptError {\n            allowRetrier(retrier, toRetry: upload, with: underlyingError)\n        } else {\n            if startRequestsImmediately { upload.resume() }\n        }\n\n        return upload\n    }\n\n    // MARK: - Internal - Retry Request\n\n    func retry(_ request: CLDNRequest) -> Bool {\n        guard let originalTask = request.originalTask else { return false }\n\n        do {\n            let task = try originalTask.CLDN_Task(session: session, adapter: adapter, queue: queue)\n\n            if let originalTask = request.task {\n                delegate[originalTask] = nil // removes the old request to avoid endless growth\n            }\n\n            request.delegate.task = task // resets all task delegate data\n\n            request.retryCount += 1\n            request.startTime = CFAbsoluteTimeGetCurrent()\n            request.endTime = nil\n\n            task.resume()\n\n            return true\n        } catch {\n            request.delegate.error = error.underlyingAdaptError ?? error\n            return false\n        }\n    }\n\n    private func allowRetrier(_ retrier: CLDNRequestRetrier, toRetry request: CLDNRequest, with error: Error) {\n        DispatchQueue.CLDNUtility.async { [weak self] in\n            guard let strongSelf = self else { return }\n\n            retrier.CLDN_Should(strongSelf, retry: request, with: error) { shouldRetry, timeDelay in\n                guard let strongSelf = self else { return }\n\n                guard shouldRetry else {\n                    if strongSelf.startRequestsImmediately { request.resume() }\n                    return\n                }\n\n                DispatchQueue.CLDNUtility.CLDN_after(timeDelay) {\n                    guard let strongSelf = self else { return }\n\n                    let retrySucceeded = strongSelf.retry(request)\n\n                    if retrySucceeded, let task = request.task {\n                        strongSelf.delegate[task] = request\n                    } else {\n                        if strongSelf.startRequestsImmediately { request.resume() }\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNTaskDelegate.swift",
    "content": "//\n//  CLDNTaskDelegate.swift\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\nimport Foundation\n\n/// The task delegate is responsible for handling all delegate callbacks for the underlying task as well as\n/// executing all operations attached to the serial operation queue upon task completion.\ninternal class CLDNTaskDelegate: NSObject {\n\n    // MARK: Properties\n\n    /// The serial operation queue used to execute all operations after the task completes.\n    internal let queue: OperationQueue\n\n    /// The data returned by the server.\n    internal var data: Data? { return nil }\n\n    /// The error generated throughout the lifecyle of the task.\n    internal var error: Error?\n\n    var task: URLSessionTask? {\n        set {\n            taskLock.lock(); defer { taskLock.unlock() }\n            _task = newValue\n        }\n        get {\n            taskLock.lock(); defer { taskLock.unlock() }\n            return _task\n        }\n    }\n\n    var initialResponseTime: CFAbsoluteTime?\n    var credential: URLCredential?\n    var metrics: AnyObject? // URLSessionTaskMetrics\n\n    private var _task: URLSessionTask? {\n        didSet { reset() }\n    }\n\n    private let taskLock = NSLock()\n\n    // MARK: Lifecycle\n\n    init(task: URLSessionTask?) {\n        _task = task\n\n        self.queue = {\n            let operationQueue = OperationQueue()\n\n            operationQueue.name = \"com.cloudinary.CLDNTaskDelegateOperationQueue\"\n            operationQueue.maxConcurrentOperationCount = 1\n            operationQueue.isSuspended = true\n            operationQueue.qualityOfService = .utility\n\n            return operationQueue\n        }()\n    }\n\n    func reset() {\n        error = nil\n        initialResponseTime = nil\n    }\n\n    // MARK: URLSessionTaskDelegate\n\n    var taskWillPerformHTTPRedirection: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest) -> URLRequest?)?\n    var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?\n    var taskNeedNewBodyStream: ((URLSession, URLSessionTask) -> InputStream?)?\n    var taskDidCompleteWithError: ((URLSession, URLSessionTask, Error?) -> Void)?\n\n    @objc(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)\n    func urlSession(\n        _ session: URLSession,\n        task: URLSessionTask,\n        willPerformHTTPRedirection response: HTTPURLResponse,\n        newRequest request: URLRequest,\n        completionHandler: @escaping (URLRequest?) -> Void)\n    {\n        var redirectRequest: URLRequest? = request\n\n        if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection {\n            redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request)\n        }\n\n        completionHandler(redirectRequest)\n    }\n\n    @objc(URLSession:task:didReceiveChallenge:completionHandler:)\n    func urlSession(\n        _ session: URLSession,\n        task: URLSessionTask,\n        didReceive challenge: URLAuthenticationChallenge,\n        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)\n    {\n        var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling\n        var credential: URLCredential?\n\n        if let taskDidReceiveChallenge = taskDidReceiveChallenge {\n            (disposition, credential) = taskDidReceiveChallenge(session, task, challenge)\n        } else {\n            if challenge.previousFailureCount > 0 {\n                disposition = .rejectProtectionSpace\n            } else {\n                credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace)\n\n                if credential != nil {\n                    disposition = .useCredential\n                }\n            }\n        }\n\n        completionHandler(disposition, credential)\n    }\n\n    @objc(URLSession:task:needNewBodyStream:)\n    func urlSession(\n        _ session: URLSession,\n        task: URLSessionTask,\n        needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)\n    {\n        var bodyStream: InputStream?\n\n        if let taskNeedNewBodyStream = taskNeedNewBodyStream {\n            bodyStream = taskNeedNewBodyStream(session, task)\n        }\n\n        completionHandler(bodyStream)\n    }\n\n    @objc(URLSession:task:didCompleteWithError:)\n    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {\n        if let taskDidCompleteWithError = taskDidCompleteWithError {\n            taskDidCompleteWithError(session, task, error)\n        } else {\n            if let error = error {\n                if self.error == nil { self.error = error }\n\n            }\n\n            queue.isSuspended = false\n        }\n    }\n}\n\n// MARK: -\n\nclass CLDNDataTaskDelegate: CLDNTaskDelegate, URLSessionDataDelegate {\n\n    // MARK: Properties\n\n    var dataTask: URLSessionDataTask { return task as! URLSessionDataTask }\n\n    override var data: Data? {\n        if dataStream != nil {\n            return nil\n        } else {\n            return mutableData\n        }\n    }\n\n    var progress: Progress\n    var progressHandler: (closure: CLDNRequest.ProgressHandler, queue: DispatchQueue)?\n\n    var dataStream: ((_ data: Data) -> Void)?\n\n    private var totalBytesReceived: Int64 = 0\n    private var mutableData: Data\n\n    private var expectedContentLength: Int64?\n\n    // MARK: Lifecycle\n\n    override init(task: URLSessionTask?) {\n        mutableData = Data()\n        progress = Progress(totalUnitCount: 0)\n\n        super.init(task: task)\n    }\n\n    override func reset() {\n        super.reset()\n\n        progress = Progress(totalUnitCount: 0)\n        totalBytesReceived = 0\n        mutableData = Data()\n        expectedContentLength = nil\n    }\n\n    // MARK: URLSessionDataDelegate\n\n    var dataTaskDidReceiveResponse: ((URLSession, URLSessionDataTask, URLResponse) -> URLSession.ResponseDisposition)?\n    var dataTaskDidBecomeDownloadTask: ((URLSession, URLSessionDataTask, URLSessionDownloadTask) -> Void)?\n    var dataTaskDidReceiveData: ((URLSession, URLSessionDataTask, Data) -> Void)?\n    var dataTaskWillCacheResponse: ((URLSession, URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)?\n\n    func urlSession(\n        _ session: URLSession,\n        dataTask: URLSessionDataTask,\n        didReceive response: URLResponse,\n        completionHandler: @escaping (URLSession.ResponseDisposition) -> Void)\n    {\n        var disposition: URLSession.ResponseDisposition = .allow\n\n        expectedContentLength = response.expectedContentLength\n\n        if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse {\n            disposition = dataTaskDidReceiveResponse(session, dataTask, response)\n        }\n\n        completionHandler(disposition)\n    }\n\n    func urlSession(\n        _ session: URLSession,\n        dataTask: URLSessionDataTask,\n        didBecome downloadTask: URLSessionDownloadTask)\n    {\n        dataTaskDidBecomeDownloadTask?(session, dataTask, downloadTask)\n    }\n\n    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {\n        if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }\n\n        if let dataTaskDidReceiveData = dataTaskDidReceiveData {\n            dataTaskDidReceiveData(session, dataTask, data)\n        } else {\n            if let dataStream = dataStream {\n                dataStream(data)\n            } else {\n                mutableData.append(data)\n            }\n\n            let bytesReceived = Int64(data.count)\n            totalBytesReceived += bytesReceived\n            let totalBytesExpected = dataTask.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown\n\n            progress.totalUnitCount = totalBytesExpected\n            progress.completedUnitCount = totalBytesReceived\n\n            if let progressHandler = progressHandler {\n                progressHandler.queue.async { progressHandler.closure(self.progress) }\n            }\n        }\n    }\n\n    func urlSession(\n        _ session: URLSession,\n        dataTask: URLSessionDataTask,\n        willCacheResponse proposedResponse: CachedURLResponse,\n        completionHandler: @escaping (CachedURLResponse?) -> Void)\n    {\n        var cachedResponse: CachedURLResponse? = proposedResponse\n\n        if let dataTaskWillCacheResponse = dataTaskWillCacheResponse {\n            cachedResponse = dataTaskWillCacheResponse(session, dataTask, proposedResponse)\n        }\n\n        completionHandler(cachedResponse)\n    }\n}\n\n// MARK: -\n\nclass CLDNUploadTaskDelegate: CLDNDataTaskDelegate {\n\n    // MARK: Properties\n\n    var uploadTask: URLSessionUploadTask { return task as! URLSessionUploadTask }\n\n    var uploadProgress: Progress\n    var uploadProgressHandler: (closure: CLDNRequest.ProgressHandler, queue: DispatchQueue)?\n\n    // MARK: Lifecycle\n\n    override init(task: URLSessionTask?) {\n        uploadProgress = Progress(totalUnitCount: 0)\n        super.init(task: task)\n    }\n\n    override func reset() {\n        super.reset()\n        uploadProgress = Progress(totalUnitCount: 0)\n    }\n\n    // MARK: URLSessionTaskDelegate\n\n    var taskDidSendBodyData: ((URLSession, URLSessionTask, Int64, Int64, Int64) -> Void)?\n\n    func URLSession(\n        _ session: URLSession,\n        task: URLSessionTask,\n        didSendBodyData bytesSent: Int64,\n        totalBytesSent: Int64,\n        totalBytesExpectedToSend: Int64)\n    {\n        if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }\n\n        if let taskDidSendBodyData = taskDidSendBodyData {\n            taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend)\n        } else {\n            uploadProgress.totalUnitCount = totalBytesExpectedToSend\n            uploadProgress.completedUnitCount = totalBytesSent\n\n            if let uploadProgressHandler = uploadProgressHandler {\n                uploadProgressHandler.queue.async { uploadProgressHandler.closure(self.uploadProgress) }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNTimeline.swift",
    "content": "//\n//  CLDNTimeline.swift\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\nimport Foundation\n\n/// Responsible for computing the timing metrics for the complete lifecycle of a `CLDNRequest`.\ninternal struct CLDNTimeline {\n    /// The time the request was initialized.\n    internal let requestStartTime: CFAbsoluteTime\n\n    /// The time the first bytes were received from or sent to the server.\n    internal let initialResponseTime: CFAbsoluteTime\n\n    /// The time when the request was completed.\n    internal let requestCompletedTime: CFAbsoluteTime\n\n    /// The time when the response serialization was completed.\n    internal let serializationCompletedTime: CFAbsoluteTime\n\n    /// The time interval in seconds from the time the request started to the initial response from the server.\n    internal let latency: TimeInterval\n\n    /// The time interval in seconds from the time the request started to the time the request completed.\n    internal let requestDuration: TimeInterval\n\n    /// The time interval in seconds from the time the request completed to the time response serialization completed.\n    internal let serializationDuration: TimeInterval\n\n    /// The time interval in seconds from the time the request started to the time response serialization completed.\n    internal let totalDuration: TimeInterval\n\n    /// Creates a new `CLDNTimeline` instance with the specified request times.\n    ///\n    /// - parameter requestStartTime:           The time the request was initialized. Defaults to `0.0`.\n    /// - parameter initialResponseTime:        The time the first bytes were received from or sent to the server.\n    ///                                         Defaults to `0.0`.\n    /// - parameter requestCompletedTime:       The time when the request was completed. Defaults to `0.0`.\n    /// - parameter serializationCompletedTime: The time when the response serialization was completed. Defaults\n    ///                                         to `0.0`.\n    ///\n    /// - returns: The new `CLDNTimeline` instance.\n    internal init(\n        requestStartTime: CFAbsoluteTime = 0.0,\n        initialResponseTime: CFAbsoluteTime = 0.0,\n        requestCompletedTime: CFAbsoluteTime = 0.0,\n        serializationCompletedTime: CFAbsoluteTime = 0.0)\n    {\n        self.requestStartTime = requestStartTime\n        self.initialResponseTime = initialResponseTime\n        self.requestCompletedTime = requestCompletedTime\n        self.serializationCompletedTime = serializationCompletedTime\n\n        self.latency = initialResponseTime - requestStartTime\n        self.requestDuration = requestCompletedTime - requestStartTime\n        self.serializationDuration = serializationCompletedTime - requestCompletedTime\n        self.totalDuration = serializationCompletedTime - requestStartTime\n    }\n}\n\n// MARK: - CustomStringConvertible\n\nextension CLDNTimeline: CustomStringConvertible {\n    /// The textual representation used when written to an output stream, which includes the latency, the request\n    /// duration and the total duration.\n    internal var description: String {\n        let latency = String(format: \"%.3f\", self.latency)\n        let requestDuration = String(format: \"%.3f\", self.requestDuration)\n        let serializationDuration = String(format: \"%.3f\", self.serializationDuration)\n        let totalDuration = String(format: \"%.3f\", self.totalDuration)\n\n        // NOTE: Had to move to string concatenation due to memory leak filed as rdar://26761490. Once memory leak is\n        // fixed, we should move back to string interpolation by reverting commit 7d4a43b1.\n        let timings = [\n            \"\\\"Latency\\\": \" + latency + \" secs\",\n            \"\\\"Request Duration\\\": \" + requestDuration + \" secs\",\n            \"\\\"Serialization Duration\\\": \" + serializationDuration + \" secs\",\n            \"\\\"Total Duration\\\": \" + totalDuration + \" secs\"\n        ]\n\n        return \"Timeline: { \" + timings.joined(separator: \", \") + \" }\"\n    }\n}\n\n// MARK: - CustomDebugStringConvertible\n\nextension CLDNTimeline: CustomDebugStringConvertible {\n    /// The textual representation used when written to an output stream, which includes the request start time, the\n    /// initial response time, the request completed time, the serialization completed time, the latency, the request\n    /// duration and the total duration.\n    internal var debugDescription: String {\n        let requestStartTime = String(format: \"%.3f\", self.requestStartTime)\n        let initialResponseTime = String(format: \"%.3f\", self.initialResponseTime)\n        let requestCompletedTime = String(format: \"%.3f\", self.requestCompletedTime)\n        let serializationCompletedTime = String(format: \"%.3f\", self.serializationCompletedTime)\n        let latency = String(format: \"%.3f\", self.latency)\n        let requestDuration = String(format: \"%.3f\", self.requestDuration)\n        let serializationDuration = String(format: \"%.3f\", self.serializationDuration)\n        let totalDuration = String(format: \"%.3f\", self.totalDuration)\n\n        // NOTE: Had to move to string concatenation due to memory leak filed as rdar://26761490. Once memory leak is\n        // fixed, we should move back to string interpolation by reverting commit 7d4a43b1.\n        let timings = [\n            \"\\\"Request Start Time\\\": \" + requestStartTime,\n            \"\\\"Initial Response Time\\\": \" + initialResponseTime,\n            \"\\\"Request Completed Time\\\": \" + requestCompletedTime,\n            \"\\\"Serialization Completed Time\\\": \" + serializationCompletedTime,\n            \"\\\"Latency\\\": \" + latency + \" secs\",\n            \"\\\"Request Duration\\\": \" + requestDuration + \" secs\",\n            \"\\\"Serialization Duration\\\": \" + serializationDuration + \" secs\",\n            \"\\\"Total Duration\\\": \" + totalDuration + \" secs\"\n        ]\n\n        return \"Timeline: { \" + timings.joined(separator: \", \") + \" }\"\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/CLDNValidation.swift",
    "content": "//\n//  CLDNValidation.swift\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\nimport Foundation\n\nextension CLDNRequest {\n\n    // MARK: Helper Types\n\n    fileprivate typealias ErrorReason = CLDNError.ResponseValidationFailureReason\n\n    /// Used to represent whether validation was successful or encountered an error resulting in a failure.\n    ///\n    /// - success: The validation was successful.\n    /// - failure: The validation failed encountering the provided error.\n    internal enum ValidationResult {\n        case success\n        case failure(Error)\n    }\n\n    fileprivate struct MIMEType {\n        let type: String\n        let subtype: String\n\n        var isWildcard: Bool { return type == \"*\" && subtype == \"*\" }\n\n        init?(_ string: String) {\n            let components: [String] = {\n                let stripped = string.trimmingCharacters(in: .whitespacesAndNewlines)\n\n            #if swift(>=3.2)\n                let split = stripped[..<(stripped.range(of: \";\")?.lowerBound ?? stripped.endIndex)]\n            #else\n                let split = stripped.substring(to: stripped.range(of: \";\")?.lowerBound ?? stripped.endIndex)\n            #endif\n\n                return split.components(separatedBy: \"/\")\n            }()\n\n            if let type = components.first, let subtype = components.last {\n                self.type = type\n                self.subtype = subtype\n            } else {\n                return nil\n            }\n        }\n\n        func matches(_ mime: MIMEType) -> Bool {\n            switch (type, subtype) {\n            case (mime.type, mime.subtype), (mime.type, \"*\"), (\"*\", mime.subtype), (\"*\", \"*\"):\n                return true\n            default:\n                return false\n            }\n        }\n    }\n\n    // MARK: Properties\n\n    internal var acceptableStatusCodes: [Int] { return Array(200..<300) }\n\n    fileprivate var acceptableContentTypes: [String] {\n        if let accept = request?.value(forHTTPHeaderField: \"Accept\") {\n            return accept.components(separatedBy: \",\")\n        }\n\n        return [\"*/*\"]\n    }\n\n    // MARK: Status Code\n\n    fileprivate func validate<S: Sequence>(\n        statusCode acceptableStatusCodes: S,\n        response: HTTPURLResponse)\n        -> ValidationResult\n        where S.Iterator.Element == Int\n    {\n        if acceptableStatusCodes.contains(response.statusCode) {\n            return .success\n        } else {\n            let reason: ErrorReason = .unacceptableStatusCode(code: response.statusCode)\n            return .failure(CLDNError.responseValidationFailed(reason: reason))\n        }\n    }\n\n    // MARK: Content Type\n\n    fileprivate func validate<S: Sequence>(\n        contentType acceptableContentTypes: S,\n        response: HTTPURLResponse,\n        data: Data?)\n        -> ValidationResult\n        where S.Iterator.Element == String\n    {\n        guard let data = data, data.count > 0 else { return .success }\n\n        guard\n            let responseContentType = response.mimeType,\n            let responseMIMEType = MIMEType(responseContentType)\n        else {\n            for contentType in acceptableContentTypes {\n                if let mimeType = MIMEType(contentType), mimeType.isWildcard {\n                    return .success\n                }\n            }\n\n            let error: CLDNError = {\n                let reason: ErrorReason = .missingContentType(acceptableContentTypes: Array(acceptableContentTypes))\n                return CLDNError.responseValidationFailed(reason: reason)\n            }()\n\n            return .failure(error)\n        }\n\n        for contentType in acceptableContentTypes {\n            if let acceptableMIMEType = MIMEType(contentType), acceptableMIMEType.matches(responseMIMEType) {\n                return .success\n            }\n        }\n\n        let error: CLDNError = {\n            let reason: ErrorReason = .unacceptableContentType(\n                acceptableContentTypes: Array(acceptableContentTypes),\n                responseContentType: responseContentType\n            )\n\n            return CLDNError.responseValidationFailed(reason: reason)\n        }()\n\n        return .failure(error)\n    }\n}\n\n// MARK: -\n\nextension CLDNDataRequest {\n    /// A closure used to validate a request that takes a URL request, a URL response and data, and returns whether the\n    /// request was valid.\n    internal typealias Validation = (URLRequest?, HTTPURLResponse, Data?) -> ValidationResult\n\n    /// Validates the request, using the specified closure.\n    ///\n    /// If validation fails, subsequent calls to response handlers will have an associated error.\n    ///\n    /// - parameter validation: A closure to validate the request.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func validate(_ validation: @escaping Validation) -> Self {\n        let validationExecution: () -> Void = { [unowned self] in\n            if\n                let response = self.response,\n                self.delegate.error == nil,\n                case let .failure(error) = validation(self.request, response, self.delegate.data)\n            {\n                self.delegate.error = error\n            }\n        }\n\n        validations.append(validationExecution)\n\n        return self\n    }\n\n    /// Validates that the response has a status code in the specified sequence.\n    ///\n    /// If validation fails, subsequent calls to response handlers will have an associated error.\n    ///\n    /// - parameter range: The range of acceptable status codes.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func validate<S: Sequence>(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int {\n        return validate { [unowned self] _, response, _ in\n            return self.validate(statusCode: acceptableStatusCodes, response: response)\n        }\n    }\n\n    /// Validates that the response has a content type in the specified sequence.\n    ///\n    /// If validation fails, subsequent calls to response handlers will have an associated error.\n    ///\n    /// - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func validate<S: Sequence>(contentType acceptableContentTypes: S) -> Self where S.Iterator.Element == String {\n        return validate { [unowned self] _, response, data in\n            return self.validate(contentType: acceptableContentTypes, response: response, data: data)\n        }\n    }\n\n    /// Validates that the response has a status code in the default acceptable range of 200...299, and that the content\n    /// type matches any specified in the Accept HTTP header field.\n    ///\n    /// If validation fails, subsequent calls to response handlers will have an associated error.\n    ///\n    /// - returns: The request.\n    @discardableResult\n    internal func validate() -> Self {\n        let contentTypes = { [unowned self] in\n            self.acceptableContentTypes\n        }\n        return validate(statusCode: acceptableStatusCodes).validate(contentType: contentTypes())\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/BaseNetwork/DispatchQueue+Cloudinary.swift",
    "content": "//\n//  DispatchQueue+Cloudinary.swift\n//\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\nimport Dispatch\nimport Foundation\n\nextension DispatchQueue {\n    static var CLDNUserInteractive: DispatchQueue { return DispatchQueue.global(qos: .userInteractive) }\n    static var CLDNUserInitiated: DispatchQueue { return DispatchQueue.global(qos: .userInitiated) }\n    static var CLDNUtility: DispatchQueue { return DispatchQueue.global(qos: .utility) }\n    static var CLDNBackground: DispatchQueue { return DispatchQueue.global(qos: .background) }\n\n    func CLDN_after(_ delay: TimeInterval, execute closure: @escaping () -> Void) {\n        asyncAfter(deadline: .now() + delay, execute: closure)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/CLDAnalytics.swift",
    "content": "//\n//  CLDAnalytics.swift\n//  Cloudinary\n//\n//  Created by Adi Mizrahi on 13/07/2022.\n//\n\nimport Foundation\nimport UIKit\n@objcMembers open class CLDAnalytics: NSObject {\n\n    private final let ALGO_VERSION = \"D\"\n    private final let PRODUCT = \"A\"\n    private final let SDK = \"E\"\n    private final let OS_TYPE = \"B\"\n    private final let ERROR_SIGNATURE = \"E\"\n\n    private var sdkVersion: String? = nil\n    private var techVersion: String? = nil\n    private var osVersion: String? = nil\n    private var osType: String? = nil\n    private var featureFlag = \"0\"\n\n    public init(sdkVersion: String? = nil, techVersion: String? = nil, osType: String? = \"B\", osVersion: String? = nil, featureFlag: String? = nil) {\n        super.init()\n        self.sdkVersion = sdkVersion ?? CLDNetworkCoordinator.getVersion()\n        self.techVersion = techVersion ?? getiOSVersion()\n        self.osType = osType\n        self.osVersion = osVersion ?? getiOSVersion()\n        self.featureFlag = featureFlag ?? \"0\"\n    }\n\n\n    public func generateAnalyticsSignature(sdkVersion: String? = nil, techVersion: String? = nil, osType: String? = \"B\", osVersion: String? = nil, featureFlag: String? = nil) -> String {\n        let sdkVersion = sdkVersion ?? self.sdkVersion\n        let techVersion = techVersion ?? self.techVersion\n        let osType = osType ?? self.osType\n        let osVersion = osVersion ?? self.osVersion\n        let featureFlag = featureFlag ?? self.featureFlag\n        let swiftVersionArray = techVersion!.split(usingRegex: \"\\\\.|\\\\-\")\n        guard swiftVersionArray.count > 1, let techVersionString = generateVersionString(major: String(swiftVersionArray[0]), minor: String(swiftVersionArray[1]), patch: \"\") else {\n            return ERROR_SIGNATURE\n        }\n        let osVersionArray = osVersion!.split(usingRegex: \"\\\\.|\\\\-\")\n        guard let osVersionString = generateOSVersionString(major: String(osVersionArray[0]), minor: String(osVersionArray[1])) else {\n            return ERROR_SIGNATURE\n        }\n        let sdkVersionArray = sdkVersion!.split(usingRegex: \"\\\\.|\\\\-\")\n        guard sdkVersionArray.count > 1, let sdkVersionString = generateVersionString(major: String(sdkVersionArray[0]), minor: String(sdkVersionArray[1]), patch: String(sdkVersionArray[2])) else {\n            return ERROR_SIGNATURE\n        }\n        return \"\\(ALGO_VERSION)\\(PRODUCT)\\(SDK)\\(sdkVersionString)\\(techVersionString)\\(osType ?? OS_TYPE)\\(osVersionString)\\(featureFlag)\"\n    }\n\n    public func setSDKVersion(version: String) {\n        sdkVersion = version\n    }\n\n    public func setTechVersion(version: String) {\n        techVersion = version\n    }\n\n    public func setOsVersion(version: String) {\n        osVersion = version\n    }\n\n    public func setFeatureFlag(flag: String? = nil) {\n        guard let flag = flag else {\n            featureFlag = \"0\"\n            return\n        }\n        featureFlag = flag\n    }\n\n    private func generateOSVersionString(major: String, minor: String) -> String? {\n        let majorVersionString = major.leftPadding(toLength: 2, withPad: \"0\")\n        let minorVersionString = minor.leftPadding(toLength: 2, withPad: \"0\")\n        guard let majorDoubleValue = Int(majorVersionString), let minorDoubleValue = Int(minorVersionString) else {\n            return nil\n        }\n        let majorString = String(majorDoubleValue, radix: 2)\n        let minorString = String(minorDoubleValue, radix: 2)\n        let majorStr = majorString.toAnalyticsVersionStr()\n        let minorStr = minorString.toAnalyticsVersionStr()\n        \n        return \"\\(majorStr)\\(minorStr)\"\n    }\n\n    private func generateVersionString(major: String, minor: String, patch: String) -> String? {\n        let versionString = (patch.leftPadding(toLength: 2, withPad: \"0\") + minor.leftPadding(toLength: 2, withPad: \"0\") + major.leftPadding(toLength: 2, withPad: \"0\"))\n        guard let doubleValue = Int(versionString) else {\n            return nil\n        }\n        let hexString = String(doubleValue, radix: 2).leftPadding(toLength: 18, withPad: \"0\")\n\n\n        var patchStr = \"\"\n        if (!patch.isEmpty) {\n            patchStr = String(hexString[hexString.startIndex..<hexString.index(hexString.startIndex, offsetBy: 6)]).toAnalyticsVersionStr()\n        }\n        let minorStr = String(hexString[hexString.index(hexString.startIndex, offsetBy: 6)..<hexString.index(hexString.startIndex, offsetBy: 12)]).toAnalyticsVersionStr()\n        let majorStr = String(hexString[hexString.index(hexString.startIndex, offsetBy: 12)..<hexString.index(hexString.startIndex, offsetBy: 18)]).toAnalyticsVersionStr()\n\n        return \"\\(patchStr)\\(minorStr)\\(majorStr)\"\n    }\n\n    private func getiOSVersion() -> String {\n        return UIDevice.current.systemVersion\n    }\n}\nextension String {\n    func split(usingRegex pattern: String) -> [String] {\n        //### Crashes when you pass invalid `pattern`\n        let regex = try! NSRegularExpression(pattern: pattern)\n        let matches = regex.matches(in: self, range: NSRange(0..<utf16.count))\n        let ranges = [startIndex..<startIndex] + matches.map{Range($0.range, in: self)!} + [endIndex..<endIndex]\n        return (0...matches.count).map {String(self[ranges[$0].upperBound..<ranges[$0+1].lowerBound])}\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/CLDCloudinary.swift",
    "content": "//\n//  CLDCloudinary.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport UIKit\n\npublic typealias CLDCompletionHandler = (_ responseImage: UIImage?, _ error: NSError?) -> ()\npublic typealias CLDAssetCompletionHandler = (_ responseAsset: Data?, _ error: NSError?) -> ()\npublic typealias CLDUploadCompletionHandler = (_ response: CLDUploadResult?, _ error: NSError?) -> ()\n\n@objcMembers open class CLDCloudinary: NSObject {\n\n    /**\n     Holds the configuration parameters to be used by the `CLDCloudinary` instance.\n     */\n    open fileprivate(set) var config: CLDConfiguration\n\n    /**\n     The network coordinator coordinates between the SDK's API level classes to its network adapter layer.\n     */\n    fileprivate var networkCoordinator: CLDNetworkCoordinator\n\n    /**\n     The network download coordinator coordinates between the SDK's API level classes to its network adapter layer.\n     */\n    fileprivate var downloadCoordinator: CLDDownloadCoordinator\n\n    // MARK: - SDK Configurations\n\n    // MARK: Log Level\n\n    /**\n     Sets Cloudinary SDK's log level, default level is set to **None**.\n     */\n    public static var logLevel: CLDLogLevel {\n        get {\n            return CLDLogManager.minimumLogLevel\n        }\n        set {\n            CLDLogManager.minimumLogLevel = newValue\n        }\n    }\n\n    // MARK: Image Cache\n\n    open var enableUrlCache: Bool {\n        get {\n            return CLDDownloadCoordinator.enableCache\n        }\n        set {\n            CLDDownloadCoordinator.enableCache = newValue\n        }\n    }\n\n    /**\n     Sets Cloudinary SDK's image cache maximum disk capacity.\n     default is 150 MB.\n     */\n    open var cacheMaxDiskCapacity: Int {\n        get {\n            return CLDDownloadCoordinator.urlCache.diskCapacity\n        }\n        set {\n            CLDDownloadCoordinator.urlCache.diskCapacity = newValue\n        }\n    }\n\n    /**\n     Sets Cloudinary SDK's image cache maximum memory total cost.\n     default is 30 MB.\n     */\n    open var cacheMaxMemoryTotalCost: Int {\n        get {\n            return CLDDownloadCoordinator.urlCache.memoryCapacity\n        }\n        set {\n            CLDDownloadCoordinator.urlCache.memoryCapacity = newValue\n        }\n    }\n\n    // MARK: - Init\n\n    /**\n    Initializes the `CLDCloudinary` instance with the specified configuration and network adapter.\n     \n    - parameter configuration:          The configuration used by this CLDCloudinary instance.\n    - parameter networkAdapter:         A network adapter that implements `CLDNetworkAdapter`. CLDNetworkDelegate() by default.\n    \n     - returns: The new `CLDCloudinary` instance.\n     */\n    public convenience init(configuration: CLDConfiguration, networkAdapter: CLDNetworkAdapter? = nil, sessionConfiguration: URLSessionConfiguration? = nil) {\n\n        self.init(configuration: configuration, networkAdapter: networkAdapter, downloadAdapter: nil, sessionConfiguration: sessionConfiguration, downloadSessionConfiguration: nil)\n    }\n    \n    /**\n    Initializes the `CLDCloudinary` instance with the specified configuration and network adapter.\n     \n    - parameter configuration:                The configuration used by this CLDCloudinary instance.\n    - parameter networkAdapter:               A network adapter that implements `CLDNetworkAdapter`.\n    - parameter downloadAdapter:              A download adapter that implements `CLDNetworkAdapter`.\n    - parameter sessionConfiguration:         A session configuration that implements `URLSessionConfiguration`.\n    - parameter downloadSessionConfiguration: A download session configuration that implements `URLSessionConfiguration`.\n     CLDNetworkDelegate() by default.\n    \n     - returns: The new `CLDCloudinary` instance.\n     */\n    public init(configuration: CLDConfiguration, networkAdapter: CLDNetworkAdapter? = nil, downloadAdapter: CLDNetworkAdapter? = nil, sessionConfiguration: URLSessionConfiguration? = nil, downloadSessionConfiguration: URLSessionConfiguration? = nil) {\n        \n        config = configuration\n        if let customNetworkAdapter = networkAdapter {\n            networkCoordinator = CLDNetworkCoordinator(configuration: config, networkAdapter: customNetworkAdapter)\n        } else {\n            if let sessionConfiguration = sessionConfiguration {\n                networkCoordinator = CLDNetworkCoordinator(configuration: config, sessionConfiguration: sessionConfiguration)\n            } else {\n                networkCoordinator = CLDNetworkCoordinator(configuration: config)\n            }\n        }\n        \n        if let customDownloadAdapter = downloadAdapter {\n            downloadCoordinator = CLDDownloadCoordinator(configuration: config, networkAdapter: customDownloadAdapter)\n        } else {\n            if let downloadSessionConfiguration = downloadSessionConfiguration {\n                downloadCoordinator = CLDDownloadCoordinator(configuration: config, sessionConfiguration: downloadSessionConfiguration)\n            } else {\n                downloadCoordinator = CLDDownloadCoordinator(configuration: config)\n            }\n        }\n        \n        super.init()\n    }\n\n    // MARK: Factory Methods\n\n    /**\n    A factory method to create a new `CLDUrl` instance\n    \n    - returns: A new `CLDUrl` instance.\n    */\n    open func createUrl() -> CLDUrl {\n        return CLDUrl(configuration: config)\n    }\n\n    /**\n     A factory method to create a new `CLDUploader` instance\n     \n     - returns: A new `CLDUploader` instance.\n     */\n    open func createUploader() -> CLDUploader {\n        return CLDUploader(networkCoordinator: networkCoordinator)\n    }\n\n    /**\n     A factory method to create a new `CLDDownloader` instance\n     \n     - returns: A new `CLDDownloader` instance.\n     */\n    open func createDownloader() -> CLDDownloader {\n        return CLDDownloader(downloadCoordinator: downloadCoordinator)\n    }\n\n    /**\n     A factory method to create a new `CLDAdminApi` instance\n     \n     - returns: A new `CLDAdminApi` instance.\n     */\n    open func createManagementApi() -> CLDManagementApi {\n        return CLDManagementApi(networkCoordinator: networkCoordinator)\n    }\n\n    // MARK: - Network Adapter\n\n    /**\n    The maximum number of queued downloads that can execute at the same time.\n    \n    default is NSOperationQueueDefaultMaxConcurrentOperationCount.\n    \n    - parameter maxConcurrentDownloads:     The maximum concurrent downloads to allow.\n    */\n    @available(iOS 8.0, *)\n    open func setMaxConcurrentDownloads(_ maxConcurrentDownloads: Int) {\n        networkCoordinator.setMaxConcurrentDownloads(maxConcurrentDownloads)\n    }\n\n    // MARK: Background Session\n\n    /**\n        Set a completion handler provided by the UIApplicationDelegate `application:handleEventsForBackgroundURLSession:completionHandler:` method.\n        The handler will be called automatically once the session finishes its events for background URL session.\n    \n        default is `nil`.\n    */\n    @available(iOS 8.0, *)\n    open func setBackgroundCompletionHandler(_ newValue: (() -> ())?) {\n        networkCoordinator.setBackgroundCompletionHandler(newValue)\n    }\n\n    // MARK: - Advanced\n    /**\n    Sets the \"USER-AGENT\" HTTP header on all network requests to be **\"PlatformName/ver CloudinaryiOS/ver\"**\n    By default the header is set to **\"CloudinaryiOS/ver\"**\n    */\n    open func setUserPlatform(_ platformName: String, version: String) {\n        config.setUserPlatform(platformName, version: version)\n    }\n\n    open func setExtraHeaderes(_ extraHeaders: [String: String]) {\n        networkCoordinator.setExtraHeaders(extraHeaders)\n    }\n\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/CLDCompatibility.swift",
    "content": "//\n// Created by Amir on 05/11/2017.\n// Copyright (c) 2017 Cloudinary. All rights reserved.\n//\n\nimport Foundation\n\n#if swift(>=4.0)\ninternal extension NSTextCheckingResult {\n    func rangeAt(_ idx:Int) -> NSRange {\n        return range(at: idx)\n    }\n}\n#endif\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/CLDConfiguration.swift",
    "content": "//\n//  CLDConfiguration.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The CLDConfiguration class holds the configuration parameters to be used by the `CLDCloudinary` instance.\n */\n@objcMembers open class CLDConfiguration: NSObject {\n    \n    fileprivate struct Defines {\n        fileprivate static let ENV_VAR_CLOUDINARY_URL = \"CLOUDINARY_URL\"\n    }\n    \n    /**\n     Your account's cloud name on Cloudinary.\n     */\n    open fileprivate(set) var cloudName: String!\n    \n    /**\n     Your account's API key, can be found in your account's dashboard on Cloudinary as part of the account details.\n     */\n    open fileprivate(set) var apiKey: String?\n    \n    /**\n     Your account's API secret, can be found in your account's dashboard on Cloudinary as part of the account details.\n     */\n    open fileprivate(set) var apiSecret: String?\n    \n    /**\n     A boolean value specifying whether or not to use a private CDN. false by default.\n     */\n    open fileprivate(set) var privateCdn: Bool = false\n    \n    /**\n     A boolean value specifying whether or not to use a secure CDN connection. false by default.\n     */\n    open fileprivate(set) var secure: Bool = true\n    \n    /**\n     A boolean value specifying whether or not to use a CDN subdomain. false by default.\n     */\n    open fileprivate(set) var cdnSubdomain: Bool = false\n    \n    /**\n     A boolean value specifying whether or not to use a secure connection with a CDN subdomain. false by default.\n     */\n    open fileprivate(set) var secureCdnSubdomain: Bool = false\n    \n    /**\n     A boolean value specifying whether or not to use long encryption. false by default.\n     */\n    open fileprivate(set) var longUrlSignature: Bool = false\n    \n    /**\n     An enum value specifying the desired hash algorithm. sha1 by default.\n     */\n    open fileprivate(set) var signatureAlgorithm: SignatureAlgorithm = .sha1\n\n    /**\n        A int value specifying the signature version to use.\n     */\n    open fileprivate(set) var signatureVesion : Int = 2\n\n    /**\n     Your secure distribution domain to be set when using a secure distribution (advanced plan only). nil by default.\n     */\n    open fileprivate(set) var secureDistribution: String?\n    \n    /**\n     Your custom domain. nil by default.\n     */\n    open fileprivate(set) var cname: String?\n    \n    /**\n     A custom upload prefix to be used instead of Cloudinary's default API prefix. nil by default.\n     */\n    open fileprivate(set) var uploadPrefix: String?\n    \n    /**\n     A custom timeout in milliseconds to be used instead of Cloudinary's default timeout. nil by default.\n     */\n    open fileprivate(set) var timeout: NSNumber?\n\n    /**\n     A boolean value specifying whether or not to use analytics. true by default.\n    */\n    open var analytics: Bool = true\n\n\n    /**\n     An analytics object\n    */\n    open var analyticsObject: CLDAnalytics = CLDAnalytics()\n\n\n    internal var userPlatform: CLDUserPlatform?\n    \n    // MARK: - Init\n    fileprivate override init() {\n        super.init()\n    }\n    \n    /**\n     Initializes a CLDConfiguration instance, using the URL specified in the environment parameters under `CLOUDINARY_URL`.\n     The URL should be in this form: `cloudinary://<API_KEY>:<API_SECRET>@<CLOUD_NAME>`.\n     Extra parameters may be added to the url: `secure` (boolean), `cdn_subdomain` (boolean), `secure_cdn_distribution` (boolean), `long_url_signature`(boolean), `cname`, `upload_prefix`, `signature_algorithm`\n     \n     - returns:                             A new `CLDConfiguration` instance if the environment parameter URL exists and is valid, otherwise returns nil.\n     \n     */\n    public static func initWithEnvParams() -> CLDConfiguration? {\n        let dict = ProcessInfo.processInfo.environment\n        if let url = dict[Defines.ENV_VAR_CLOUDINARY_URL], validateUrl(url: url) {\n            return CLDConfiguration(cloudinaryUrl: url)\n        }\n        \n        return nil\n    }\n    \n    internal static func validateUrl(url: String) -> Bool{\n        return url.starts(with: \"cloudinary://\")\n    }\n    \n    public init?(options: [String : AnyObject]) {\n        guard let\n            cloudName = options[ConfigParam.CloudName.rawValue] as? String else {\n                return nil\n        }\n        \n        \n        self.cloudName = cloudName\n        \n        for key in options.keys {\n            if let option = ConfigParam(rawValue: key) {\n                switch option {\n                case .Secure:\n                    if let value = options[ConfigParam.Secure.rawValue] as? Bool {\n                        secure = value\n                    }\n                    else if let value = options[ConfigParam.Secure.rawValue] as? String {\n                        secure = value.cldAsBool()\n                    }\n                    break\n                case .CdnSubdomain:\n                    if let value = options[ConfigParam.CdnSubdomain.rawValue] as? Bool {\n                        cdnSubdomain = value\n                    }\n                    else if let value = options[ConfigParam.CdnSubdomain.rawValue] as? String {\n                        cdnSubdomain = value.cldAsBool()\n                    }\n                    break\n                case .SecureCdnSubdomain:\n                    if let value = options[ConfigParam.SecureCdnSubdomain.rawValue] as? Bool {\n                        secureCdnSubdomain = value\n                    }\n                    else if let value = options[ConfigParam.SecureCdnSubdomain.rawValue] as? String {\n                        secureCdnSubdomain = value.cldAsBool()\n                    }\n                    break\n                case .LongUrlSignature:\n                    if let value = options[ConfigParam.LongUrlSignature.rawValue] as? Bool {\n                        longUrlSignature = value\n                    }\n                    else if let value = options[ConfigParam.LongUrlSignature.rawValue] as? String {\n                        longUrlSignature = value.cldAsBool()\n                    }\n                    break\n                case .SignatureAlgorithm:\n                    if let value = options[ConfigParam.SignatureAlgorithm.rawValue] as? SignatureAlgorithm {\n                        signatureAlgorithm = value\n                    }\n                    else if let value = options[ConfigParam.SignatureAlgorithm.rawValue] as? String {\n                        signatureAlgorithm = SignatureAlgorithm(stringValue: value)\n                    }\n                    break\n                case .SignatureVersion:\n                    if let value = options[ConfigParam.SignatureVersion.rawValue] as? Int {\n                        signatureVesion = value\n                    }\n                case .CName:\n                    if let value = options[ConfigParam.CName.rawValue] as? String {\n                        cname = value\n                    }\n                    break\n                case .UploadPrefix:\n                    if let value = options[ConfigParam.UploadPrefix.rawValue] as? String {\n                        uploadPrefix = value\n                    }\n                    break\n                case .APISecret:\n                    if let value = options[ConfigParam.APISecret.rawValue] as? String {\n                        apiSecret = value\n                    }\n                    break\n                case .APIKey:\n                    if let value = options[ConfigParam.APIKey.rawValue] as? String {\n                        apiKey = value\n                    }\n                    break\n                case .PrivateCdn:\n                    if let value = options[ConfigParam.PrivateCdn.rawValue] as? Bool {\n                        privateCdn = value\n                    }\n                    else if let value = options[ConfigParam.PrivateCdn.rawValue] as? String {\n                        privateCdn = value.cldAsBool()\n                    }\n                    break\n                case .SecureDistribution:\n                    if let value = options[ConfigParam.SecureDistribution.rawValue] as? String {\n                        secureDistribution = value\n                    }\n                    break\n                case .Timeout:\n                    if let value = options[ConfigParam.Timeout.rawValue] as? NSNumber {\n                        timeout = value\n                    }\n                    else if let value = options[ConfigParam.Timeout.rawValue] as? String {\n                        timeout = value.cldAsNSNumber()\n                    }\n                    break\n                default:\n                    break\n                }\n            }\n        }\n    }\n    \n    /**\n     Initializes a CLDConfiguration instance with the specified parameters.\n     \n     - parameter cloudName:                 Your account's cloud name on Cloudinary.\n     - parameter apiKey:                    Your account's API key, can be found in your account's dashboard on Cloudinary as part of the account details.\n     - parameter apiSecret:                 Your account's API secret, can be found in your account's dashboard on Cloudinary as part of the account details.\n     - parameter privateCdn:                A boolean value specifying whether or not to use a private CDN. false by default.\n     - parameter secure:                    A boolean value specifying whether or not to use a secure CDN connection. false by default.\n     - parameter cdnSubdomain:              A boolean value specifying whether or not to use a CDN subdomain. false by default.\n     - parameter secureCdnSubdomain:        A boolean value specifying whether or not to use a secure connection with a CDN subdomain. false by default.\n     - parameter longUrlSignature:          A boolean value specifying whether or not to use long encryption. false by default.\n     - parameter signatureAlgorithm:        An enum value specifying the desired hash algorithm. sha1 by default.\n     - parameter secureDistribution:        Set your secure distribution domain to be set when using a secure distribution (advanced plan only). nil by default.\n     - parameter cname:                     Set your custom domain. nil by default.\n     - parameter uploadPrefix:              Set a custom upload prefix to be used instead of Cloudinary's default API prefix. nil by default.\n     - parameter timeout:                   A custom timeout in milliseconds to be used instead of Cloudinary's default timeout. nil by default.\n     \n     - returns:                             A new `CLDConfiguration` instance.\n     \n     */\n    public init(\n        cloudName: String,\n        apiKey: String? = nil,\n        apiSecret: String? = nil,\n        privateCdn: Bool = false,\n        secure: Bool = false,\n        cdnSubdomain: Bool = false,\n        secureCdnSubdomain: Bool = false,\n        longUrlSignature: Bool = false,\n        signatureAlgorithm: SignatureAlgorithm = .sha1,\n        signatureVersion: Int = 2,\n        secureDistribution: String? = nil,\n        cname: String? = nil,\n        uploadPrefix: String? = nil,\n        timeout: NSNumber? = nil,\n        analytics: Bool = true\n    ) {\n        self.cloudName = cloudName\n        self.apiKey = apiKey\n        self.apiSecret = apiSecret\n        self.privateCdn = privateCdn\n        self.secure = secure\n        self.cdnSubdomain = cdnSubdomain\n        self.secureCdnSubdomain = secureCdnSubdomain\n        self.longUrlSignature = longUrlSignature\n        self.signatureAlgorithm = signatureAlgorithm\n        self.signatureVesion = signatureVersion\n        self.secureDistribution = secureDistribution\n        self.cname = cname\n        self.uploadPrefix = uploadPrefix\n        self.timeout = timeout\n        self.analytics = analytics\n        super.init()\n    }\n    \n    /**\n     Initializes a CLDConfiguration instance, using a given URL.\n     The URL should be in this form: `cloudinary://<API_KEY>:<API_SECRET>@<CLOUD_NAME>`.\n     Extra parameters may be added to the url: `secure` (boolean), `cdn_subdomain` (boolean), `secure_cdn_distribution` (boolean), `long_url_signature`(boolean), `cname`, `upload_prefix`, `signature_algorithm`\n     \n     - returns:                             A new `CLDConfiguration` instance if the URL is valid, otherwise returns nil.\n     \n     */\n    public init?(cloudinaryUrl: String) {\n        super.init()\n        \n        guard let\n            uri = URL(string: cloudinaryUrl),\n            CLDConfiguration.validateUrl(url: cloudinaryUrl),\n            let cloudName = uri.host\n            else {\n                return nil\n        }\n        \n        self.cloudName = cloudName\n        \n        if let apiKey = uri.user {\n            self.apiKey = apiKey\n        }\n        if let apiSecret = uri.password {\n            self.apiSecret = apiSecret\n        }\n        \n        if !uri.path.isEmpty {\n            privateCdn = true\n            let index1 = uri.path.index(uri.path.startIndex, offsetBy: 1)\n            secureDistribution = String(uri.path[index1...])\n        }\n        \n        if let queryItems = URLComponents(url: uri, resolvingAgainstBaseURL: false)?.queryItems {\n            for item in queryItems\n            {\n                guard let value = item.value else { continue }\n                \n                switch ConfigParam(rawValue: item.name) {\n                case .Secure: secure = value.cldAsBool()\n                case .CdnSubdomain: cdnSubdomain = value.cldAsBool()\n                case .SecureCdnSubdomain: secureCdnSubdomain = value.cldAsBool()\n                case .LongUrlSignature: longUrlSignature = value.cldAsBool()\n                case .SignatureAlgorithm: signatureAlgorithm = SignatureAlgorithm(stringValue: value)\n                case .SignatureVersion: signatureVesion = Int(value) ?? 2\n                case .CName: cname = value\n                case .UploadPrefix: uploadPrefix = value\n                case .Timeout: timeout = value.cldAsNSNumber()\n                case .Analytics: analytics = value.cldAsBool()\n                default:\n                    continue\n                }\n            }\n        }\n    }\n    \n    // MARK: Optional Url Params\n    internal enum ConfigParam: String, CustomStringConvertible {\n        \n        case Secure             = \"secure\"\n        case CdnSubdomain       = \"cdn_subdomain\"\n        case SecureCdnSubdomain = \"secure_cdn_subdomain\"\n        case LongUrlSignature   = \"long_url_signature\"\n        case SignatureAlgorithm = \"signature_algorithm\"\n        case SignatureVersion   = \"signature_version\"\n        case CName              = \"cname\"\n        case UploadPrefix       = \"upload_prefix\"\n        case APIKey             = \"api_key\"\n        case APISecret          = \"api_secret\"\n        case CloudName          = \"cloud_name\"\n        case PrivateCdn         = \"private_cdn\"\n        case SecureDistribution = \"secure_distribution\"\n        case Timeout            = \"timeout\"\n        case Analytics          = \"analytics\"\n        \n        internal var description: String {\n            switch self {\n            case .Secure:               return \"secure\"\n            case .CdnSubdomain:         return \"cdn_subdomain\"\n            case .SecureCdnSubdomain:   return \"secure_cdn_subdomain\"\n            case .LongUrlSignature:     return \"long_url_signature\"\n            case .SignatureAlgorithm:   return \"signature_algorithm\"\n            case .SignatureVersion:     return \"signature_version\"\n            case .CName:                return \"cname\"\n            case .UploadPrefix:         return \"upload_prefix\"\n            case .APIKey:               return \"api_key\"\n            case .APISecret:            return \"api_secret\"\n            case .CloudName:            return \"cloud_name\"\n            case .PrivateCdn:           return \"private_cdn\"\n            case .SecureDistribution:   return \"secure_distribution\"\n            case .Timeout:              return \"timeout\"\n            case .Analytics:            return \"analytics\"\n            }\n        }\n    }\n    \n    \n    // MARK: signatureAlgorithm\n    @objc public enum SignatureAlgorithm: Int, CustomStringConvertible {\n        \n        case sha1   = 0\n        case sha256 = 1\n        \n        public init(stringValue: String) {\n            switch stringValue {\n            case \"sha1\":   self = .sha1\n            case \"sha256\": self = .sha256\n            default:       self = .sha1\n            }\n        }\n        \n        public var description: String {\n            switch self {\n            case .sha1:   return \"sha1\"\n            case .sha256: return \"sha256\"\n            }\n        }\n    }\n    \n    // MARK: User Platform\n    internal func setUserPlatform(_ platformName: String, version: String) {\n        userPlatform = CLDUserPlatform(platform: platformName, version: version)\n    }\n    \n    internal func clearUserPlatform() {\n        userPlatform = nil\n    }\n    \n    internal struct CLDUserPlatform {\n        var platform: String\n        var version: String\n        \n        init(platform: String, version: String) {\n            self.platform = platform\n            self.version = version\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/CLDEagerTransformation.swift",
    "content": "//\n// Created by Nitzan Jaitman on 09/05/2018.\n// Copyright (c) 2018 Cloudinary. All rights reserved.\n//\n\nimport Foundation\n\nopen class CLDEagerTransformation: CLDTransformation {\n    /**\n     Set the format for the eager transformation\n    */\n    fileprivate var eagerFormat: String?\n\n    open func setFormat(_ format: String?) -> Self{\n        self.eagerFormat = format\n        return self;\n    }\n\n    override func getStringRepresentationFromParams(_ params: [String: String]) -> String? {\n        // return the original transformation string with a /format if set.\n        var result = \"\"\n        if let baseTransformation = super.getStringRepresentationFromParams(params) {\n            result += baseTransformation\n        }\n\n        if let format = eagerFormat {\n            result += \"/\\(format)\"\n        }\n\n        return result\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/CLDResponsiveParams.swift",
    "content": "//\n//  CLDResponsiveParams.swift\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n\nimport Foundation\n\n@objcMembers open class CLDResponsiveParams: NSObject {\n    public static let defaultStepSize = 50\n    public static let defaultMaxDimension = 350\n    public static let defaultMinDimension = 50\n    public static let defaultReloadOnSizeChange = false\n\n    internal let autoWidth: Bool\n    internal let autoHeight: Bool\n    internal let cropMode: CLDTransformation.CLDCrop?\n    internal let gravity: CLDTransformation.CLDGravity?\n    internal var shouldReloadOnSizeChange = defaultReloadOnSizeChange\n    internal var stepSizePoints = defaultStepSize\n    internal var maxDimensionPoints = defaultMaxDimension\n    internal var minDimensionPoints = defaultMinDimension\n\n    // MARK: - Init\n    public init(autoWidth: Bool, autoHeight: Bool, cropMode: CLDTransformation.CLDCrop?, gravity: CLDTransformation.CLDGravity?) {\n        self.autoWidth = autoWidth\n        self.autoHeight = autoHeight\n        self.cropMode = cropMode\n        self.gravity = gravity\n    }\n\n    // MARK: - Presets\n    public static func fit () -> CLDResponsiveParams {\n        return CLDResponsiveParams(autoWidth: true, autoHeight: true, cropMode: CLDTransformation.CLDCrop.fit, gravity: nil)\n    }\n\n    public static func autoFill () -> CLDResponsiveParams {\n        return CLDResponsiveParams(autoWidth: true, autoHeight: true, cropMode: CLDTransformation.CLDCrop.fill, gravity: CLDTransformation.CLDGravity.auto)\n    }\n\n    // MARK: - Setters\n    public func setStepSize(_ stepSize:Int) -> Self {\n        self.stepSizePoints = stepSize\n        return self\n    }\n\n    public func setMaxDimension(_ maxDimension:Int) -> Self {\n        self.maxDimensionPoints = maxDimension\n        return self\n    }\n\n    public func setMinDimension(_ minDimension:Int) -> Self {\n        self.minDimensionPoints = minDimension\n        return self\n    }\n\n    public func setReloadOnSizeChange(_ reload: Bool) -> Self {\n        self.shouldReloadOnSizeChange = reload\n        return self\n    }\n}\n\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Cloudinary.h",
    "content": "//\n//  Cloudinary.h\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <UIKit/UIKit.h>\n\n//! Project version number for Cloudinary.\nFOUNDATION_EXPORT double CloudinaryVersionNumber;\n\n//! Project version string for Cloudinary.\nFOUNDATION_EXPORT const unsigned char CloudinaryVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <Cloudinary/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/CacheSystem/Enum/HTTPStatusCode.swift",
    "content": "//\n//  HTTPStatusCode.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal enum HTTPStatusCode : Int\n{\n    case `continue`                       = 100\n    case switchingProtocols               = 101\n    case processing                       = 102\n    case checkpoint                       = 103\n    \n    case ok                               = 200\n    case created                          = 201\n    case accepted                         = 202\n    case nonAuthoritativeInformation      = 203\n    case noContent                        = 204\n    case resetContent                     = 205\n    case partialContent                   = 206\n    case multiStatus                      = 207\n    case alreadyReported                  = 208\n    case imUsed                           = 226\n    \n    case multipleChoices                  = 300\n    case movedPermenantly                 = 301\n    case found                            = 302\n    case seeOther                         = 303\n    case notModified                      = 304\n    case useProxy                         = 305\n    case temporaryRedirect                = 307\n    case permanentRedirect                = 308\n    \n    case badRequest                       = 400\n    case unauthorized                     = 401\n    case paymentRequired                  = 402\n    case forbidden                        = 403\n    case notFound                         = 404\n    case methodNotAllowed                 = 405\n    case notAcceptable                    = 406\n    case proxyAuthenticationRequired      = 407\n    case requestTimeout                   = 408\n    case conflict                         = 409\n    case gone                             = 410\n    case lengthRequired                   = 411\n    case preconditionFailed               = 412\n    case payloadTooLarge                  = 413\n    case uriTooLong                       = 414\n    case unsupportedMediaType             = 415\n    case rangeNotSatisfiable              = 416\n    case expectationFailed                = 417\n    case imATeapot                        = 418\n    case misdirectedRequest               = 421\n    case unprocesssableEntity             = 422\n    case locked                           = 423\n    case failedDependency                 = 424\n    case urpgradeRequired                 = 426\n    case preconditionRequired             = 428\n    case tooManyRequests                  = 429\n    case requestHeadersFieldTooLarge      = 431\n    case iisLoginTimeout                  = 440\n    case nginxNoResponse                  = 444\n    case iisRetryWith                     = 449\n    case blockedByWindowsParentalControls = 450\n    case unavailableForLegalReasons       = 451\n    case nginxSSLCertificateError         = 495\n    case nginxHTTPToHTTPS                 = 497\n    case tokenExpired                     = 498\n    case nginxClientClosedRequest         = 499\n    \n    case internalServerError              = 500\n    case notImplemented                   = 501\n    case badGateway                       = 502\n    case serviceUnavailable               = 503\n    case gatewayTimeout                   = 504\n    case httpVersionNotSupported          = 505\n    case variantAlsoNegotiates            = 506\n    case insufficientStorage              = 507\n    case loopDetected                     = 508\n    case bandwidthLimitExceeded           = 509\n    case notExtended                      = 510\n    case networkAuthenticationRequired    = 511\n    case siteIsFrozen                     = 530\n}\nextension HTTPStatusCode\n{\n    internal var isInformational : Bool {\n        switch rawValue {\n        case 100..<200: return true\n        default: return false\n        }\n    }\n    internal var isSuccess       : Bool {\n        switch rawValue {\n        case 200..<300: return true\n        default: return false\n        }\n    }\n    internal var isRedirection   : Bool {\n        switch rawValue {\n        case 300..<400: return true\n        default: return false\n        }\n    }\n    internal var isClientError   : Bool {\n        switch rawValue {\n        case 400..<500: return true\n        default: return false\n        }\n    }\n    internal var isServerError   : Bool {\n        switch rawValue {\n        case 500..<600: return true\n        default: return false\n        }\n    }\n    internal var isError         : Bool {\n        return self.isClientError || isServerError\n    }\n    \n    internal var localizedReason : String {\n        return HTTPURLResponse.localizedString(forStatusCode: rawValue)\n    }\n}\n\n// MARK: - CustomStringConvertible\nextension HTTPStatusCode : CustomStringConvertible\n{\n    internal var description : String {\n        return \"\\(rawValue) \\(localizedReason)\"\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Downloader/CLDDownloader.swift",
    "content": "//\n//  CLDDownloader.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The CLDDownloader class is used to asynchronously fetch images either from the image cache if they exist or download them from a remote source.\n*/\n@objcMembers open class CLDDownloader: CLDBaseNetworkObject {\n    \n    // MARK: - Init\n    internal fileprivate(set) var downloadCoordinator: CLDDownloadCoordinator!\n    \n    fileprivate override init() {\n        super.init()\n    }\n    \n    internal init(downloadCoordinator: CLDDownloadCoordinator) {\n        \n        self.downloadCoordinator = downloadCoordinator\n        super.init(networkCoordinator: downloadCoordinator)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/CLDBaseNetworkObject.swift",
    "content": "//\n//  CLDBaseNetworkObject.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDBaseNetworkObject: NSObject {\n\n    \n    internal fileprivate(set) var networkCoordinator: CLDNetworkCoordinator!\n    \n    internal override init() {\n        super.init()\n    }\n    \n    internal init(networkCoordinator: CLDNetworkCoordinator) {\n        self.networkCoordinator = networkCoordinator\n        super.init()\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/CLDConditionExpression.swift",
    "content": "//\n//  CLDConditionExpression.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDConditionExpression : CLDExpression {\n    \n    var relatedTransformation: CLDTransformation\n    \n    // MARK: - Init\n    private init(_ expression: CLDExpression) {\n        self.relatedTransformation = CLDTransformation()\n        super.init(value: expression.asInternalString())\n    }\n    \n    public override init() {\n        self.relatedTransformation = CLDTransformation()\n        super.init()\n    }\n    \n    public override init(value: String) {\n        self.relatedTransformation = CLDTransformation()\n        super.init(value: value)\n    }\n    \n    // MARK: - Public methods\n    @discardableResult\n    public func and() -> Self {\n        appendOperatorToCurrentValue(.and)\n        return self\n    }\n    @objc(andString:)\n    @discardableResult\n    public func and(_ value: String) -> Self {\n        appendingStringToCurrentValue(cldoperator: .and, inputValue: value)\n        return self\n    }\n    @objc(andExpression:)\n    @discardableResult\n    public func and(_ value: CLDExpression) -> Self {\n        return and(value.asInternalString())\n    }\n    \n    @discardableResult\n    public func or() -> Self {\n        appendOperatorToCurrentValue(.or)\n        return self\n    }\n    @objc(orString:)\n    @discardableResult\n    public func or(_ value: String) -> Self {\n        appendingStringToCurrentValue(cldoperator: .or, inputValue: value)\n        return self\n    }\n    @objc(orExpression:)\n    @discardableResult\n    public func or(_ value: CLDExpression) -> Self {\n        return or(value.asInternalString())\n    }\n    \n    @objc(equalToInt:)\n    @discardableResult\n    public func equal(to value: Int) -> Self {\n        return equal(to: String(value))\n    }\n    @objc(equalToFloat:)\n    @discardableResult\n    public func equal(to value: Float) -> Self {\n        return equal(to: value.cldFloatFormat())\n    }\n    @objc(equalToString:)\n    @discardableResult\n    public func equal(to value: String) -> Self {\n        appendingStringToCurrentValue(cldoperator: .equal, inputValue: value)\n        return self\n    }\n    @objc(equalToExpression:)\n    @discardableResult\n    public func equal(to value: CLDExpression) -> Self {\n        return equal(to: value.asInternalString())\n    }\n    \n    @objc(notEqualToInt:)\n    @discardableResult\n    public func notEqual(to value: Int) -> Self {\n        return notEqual(to: String(value))\n    }\n    @objc(notEqualToFloat:)\n    @discardableResult\n    public func notEqual(to value: Float) -> Self {\n        return notEqual(to: value.cldFloatFormat())\n    }\n    @objc(notEqualToString:)\n    @discardableResult\n    public func notEqual(to value: String) -> Self {\n        appendingStringToCurrentValue(cldoperator: .notEqual, inputValue: value)\n        return self\n    }\n    @objc(notEqualToExpression:)\n    @discardableResult\n    public func notEqual(to value: CLDExpression) -> Self {\n        return notEqual(to: value.asInternalString())\n    }\n    \n    @objc(lessThenInt:)\n    @discardableResult\n    public func less(then value: Int) -> Self {\n        return less(then: String(value))\n    }\n    @objc(lessThenFloat:)\n    @discardableResult\n    public func less(then value: Float) -> Self {\n        return less(then: value.cldFloatFormat())\n    }\n    @objc(lessThenString:)\n    @discardableResult\n    public func less(then value: String) -> Self {\n        appendingStringToCurrentValue(cldoperator: .lessThen, inputValue: value)\n        return self\n    }\n    @objc(lessThenExpression:)\n    @discardableResult\n    public func less(then value: CLDExpression) -> Self {\n        return less(then: value.asInternalString())\n    }\n    \n    @objc(greaterThenInt:)\n    @discardableResult\n    public func greater(then value: Int) -> Self {\n        return greater(then: String(value))\n    }\n    @objc(greaterThenFloat:)\n    @discardableResult\n    public func greater(then value: Float) -> Self {\n        return greater(then: value.cldFloatFormat())\n    }\n    @objc(greaterThenString:)\n    @discardableResult\n    public func greater(then value: String) -> Self {\n        appendingStringToCurrentValue(cldoperator: .greaterThen, inputValue: value)\n        return self\n    }\n    @objc(greaterThenExpression:)\n    @discardableResult\n    public func greater(then value: CLDExpression) -> Self {\n        return greater(then: value.asInternalString())\n    }\n    \n    @objc(lessOrEqualToInt:)\n    @discardableResult\n    public func lessOrEqual(to value: Int) -> Self {\n        return lessOrEqual(to: String(value))\n    }\n    @objc(lessOrEqualToFloat:)\n    @discardableResult\n    public func lessOrEqual(to value: Float) -> Self {\n        return lessOrEqual(to: value.cldFloatFormat())\n    }\n    @objc(lessOrEqualToString:)\n    @discardableResult\n    public func lessOrEqual(to value: String) -> Self {\n        appendingStringToCurrentValue(cldoperator: .lessOrEqual, inputValue: value)\n        return self\n    }\n    @objc(lessOrEqualToExpression:)\n    @discardableResult\n    public func lessOrEqual(to value: CLDExpression) -> Self {\n        return lessOrEqual(to: value.asInternalString())\n    }\n    \n    @objc(greaterOrEqualToInt:)\n    @discardableResult\n    public func greaterOrEqual(to value: Int) -> Self {\n        return greaterOrEqual(to: String(value))\n    }\n    @objc(greaterOrEqualToFloat:)\n    @discardableResult\n    public func greaterOrEqual(to value: Float) -> Self {\n        return greaterOrEqual(to: value.cldFloatFormat())\n    }\n    @objc(greaterOrEqualToString:)\n    @discardableResult\n    public func greaterOrEqual(to value: String) -> Self {\n        appendingStringToCurrentValue(cldoperator: .greaterOrEqual, inputValue: value)\n        return self\n    }\n    @objc(greaterOrEqualToExpression:)\n    @discardableResult\n    public func greaterOrEqual(to value: CLDExpression) -> Self {\n        return greaterOrEqual(to: value.asInternalString())\n    }\n    \n    @objc(insideString:)\n    @discardableResult\n    public func inside(_ expression: String) -> Self {\n        \n        guard !expression.isEmpty else { return self }\n        appendingStringToCurrentValue(cldoperator: .inside, inputValue: expression)\n        return self\n    }\n    @objc(insideExpression:)\n    @discardableResult\n    public func inside(_ expression: CLDExpression) -> Self {\n        return inside(expression.asInternalString())\n    }\n    \n    @objc(notInsideString:)\n    @discardableResult\n    public func notInside(_ expression: String) -> Self {\n        \n        guard !expression.isEmpty else { return self }\n        appendingStringToCurrentValue(cldoperator: .notInside, inputValue: expression)\n        return self\n    }\n    @objc(notInsideExpression:)\n    @discardableResult\n    public func notInside(_ expression: CLDExpression) -> Self {\n        return notInside(expression.asInternalString())\n    }\n    \n    @objc(valueFromString:)\n    @discardableResult\n    public func value(_ expression: String) -> Self {\n        \n        let expressionObject = CLDExpression.init(value: expression)\n        \n        let value: String\n        if  expressionObject.currentValue.isEmpty {\n            \n            value = expression\n        } else {\n         \n            value = expressionObject.asString()\n        }\n        \n        if !expressionObject.currentValue.isEmpty && currentKey.isEmpty {\n            currentKey      = expressionObject.currentKey\n            currentValue    = expressionObject.currentValue\n        }\n        else if expressionObject.currentValue.isEmpty && currentKey.isEmpty {\n            currentKey      = value\n        }\n        else if currentValue.isEmpty {\n           \n            currentValue.append(value)\n        } else {\n            \n            currentValue.append(CLDVariable.elementsSeparator + value)\n        }\n        return self\n    }\n    @objc(valueFromExpression:)\n    @discardableResult\n    public func value(_  expression: CLDExpression) -> Self {\n        return value(expression.asInternalString())\n    }\n    \n    // MARK: - then\n    @objc(then)\n    public func then() -> CLDTransformation {\n        \n        return relatedTransformation.ifCondition(self)\n    }\n    \n    // MARK: - Class Func\n    public override class func width() -> Self {\n        return CLDConditionExpression(super.width()) as! Self\n    }\n    public override class func height() -> Self {\n        return CLDConditionExpression(super.height()) as! Self\n    }\n    public override class func aspectRatio() -> Self {\n        return CLDConditionExpression(super.aspectRatio()) as! Self\n    }\n    \n    public override class func initialWidth() -> Self {\n        return CLDConditionExpression(super.initialWidth()) as! Self\n    }\n    public override class func initialHeight() -> Self {\n        return CLDConditionExpression(super.initialHeight()) as! Self\n    }\n    public override class func initialAspectRatio() -> Self {\n        return CLDConditionExpression(super.initialAspectRatio()) as! Self\n    }\n    \n    public override class func pageCount() -> Self {\n        return CLDConditionExpression(super.pageCount()) as! Self\n    }\n    public override class func faceCount() -> Self {\n        return CLDConditionExpression(super.faceCount()) as! Self\n    }\n    \n    public override class func tags() -> Self {\n        return CLDConditionExpression(super.tags()) as! Self\n    }\n    \n    public override class func pageXOffset() -> Self {\n        return CLDConditionExpression(super.pageXOffset()) as! Self\n    }\n    public override class func pageYOffset() -> Self {\n        return CLDConditionExpression(super.pageYOffset()) as! Self\n    }\n    \n    public override class func illustrationScore() -> Self {\n        return CLDConditionExpression(super.illustrationScore()) as! Self\n    }\n    \n    public override class func currentPageIndex() -> Self {\n        return CLDConditionExpression(super.currentPageIndex()) as! Self\n    }\n    public override class func duration() -> Self {\n        return CLDConditionExpression(super.duration()) as! Self\n    }\n    public override class func initialDuration() -> Self {\n        return CLDConditionExpression(super.initialDuration()) as! Self\n    }\n    \n    \n    // MARK: - helper methods\n    @objc(width:intValue:)\n    @discardableResult\n    public func width(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .width, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(width:floatValue:)\n    @discardableResult\n    public func width(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .width, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(width:string:)\n    @discardableResult\n    public func width(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .width, operatorString: operatorString, inputValue: object)\n    }\n    @objc(width:expression:)\n    @discardableResult\n    public func width(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .width, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(width:conditionExpression:)\n    @discardableResult\n    public func width(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .width, operatorString: operatorString, inputValue: object.asString())\n    }\n    \n    @objc(height:intValue:)\n    @discardableResult\n    public func height(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .height, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(height:floatValue:)\n    @discardableResult\n    public func height(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .height, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(height:string:)\n    @discardableResult\n    public func height(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .height, operatorString: operatorString, inputValue: object)\n    }\n    @objc(height:expression:)\n    @discardableResult\n    public func height(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .height, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(height:conditionExpression:)\n    @discardableResult\n    public func height(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .height, operatorString: operatorString, inputValue: object.asString())\n    }\n    \n    @objc(aspectRatio:intValue:)\n    @discardableResult\n    public func aspectRatio(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .aspectRatio, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(aspectRatio:floatValue:)\n    @discardableResult\n    public func aspectRatio(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .aspectRatio, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(aspectRatio:string:)\n    @discardableResult\n    public func aspectRatio(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .aspectRatio, operatorString: operatorString, inputValue: object)\n    }\n    @objc(aspectRatio:expression:)\n    @discardableResult\n    public func aspectRatio(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .aspectRatio, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(aspectRatio:conditionExpression:)\n    @discardableResult\n    public func aspectRatio(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .aspectRatio, operatorString: operatorString, inputValue: object.asString())\n    }\n    \n    @objc(initialWidth:intValue:)\n    @discardableResult\n    public func initialWidth(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .initialWidth, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(initialWidth:floatValue:)\n    @discardableResult\n    public func initialWidth(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .initialWidth, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(initialWidth:string:)\n    @discardableResult\n    public func initialWidth(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .initialWidth, operatorString: operatorString, inputValue: object)\n    }\n    @objc(initialWidth:expression:)\n    @discardableResult\n    public func initialWidth(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .initialWidth, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(initialWidth:conditionExpression:)\n    @discardableResult\n    public func initialWidth(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .initialWidth, operatorString: operatorString, inputValue: object.asString())\n    }\n    \n    @objc(initialHeight:intValue:)\n    @discardableResult\n    public func initialHeight(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .initialHeight, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(initialHeight:floatValue:)\n    @discardableResult\n    public func initialHeight(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .initialHeight, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(initialHeight:string:)\n    @discardableResult\n    public func initialHeight(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .initialHeight, operatorString: operatorString, inputValue: object)\n    }\n    @objc(initialHeight:expression:)\n    @discardableResult\n    public func initialHeight(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .initialHeight, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(initialHeight:conditionExpression:)\n    @discardableResult\n    public func initialHeight(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .initialHeight, operatorString: operatorString, inputValue: object.asString())\n    }\n\n    @objc(initialAspectRatio:intValue:)\n    @discardableResult\n    public func initialAspectRatio(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .initialAspectRatio, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(initialAspectRatio:floatValue:)\n    @discardableResult\n    public func initialAspectRatio(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .initialAspectRatio, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(initialAspectRatio:string:)\n    @discardableResult\n    public func initialAspectRatio(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .initialAspectRatio, operatorString: operatorString, inputValue: object)\n    }\n    @objc(initialAspectRatio:expression:)\n    @discardableResult\n    public func initialAspectRatio(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .initialAspectRatio, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(initialAspectRatio:conditionExpression:)\n    @discardableResult\n    public func initialAspectRatio(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .initialAspectRatio, operatorString: operatorString, inputValue: object.asString())\n    }\n\n    @objc(pageCount:intValue:)\n    @discardableResult\n    public func pageCount(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .pageCount, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(pageCount:floatValue:)\n    @discardableResult\n    public func pageCount(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .pageCount, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(pageCount:string:)\n    @discardableResult\n    public func pageCount(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .pageCount, operatorString: operatorString, inputValue: object)\n    }\n    @objc(pageCount:expression:)\n    @discardableResult\n    public func pageCount(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .pageCount, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(pageCount:conditionExpression:)\n    @discardableResult\n    public func pageCount(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .pageCount, operatorString: operatorString, inputValue: object.asString())\n    }\n\n    @objc(faceCount:intValue:)\n    @discardableResult\n    public func faceCount(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .faceCount, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(faceCount:floatValue:)\n    @discardableResult\n    public func faceCount(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .faceCount, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(faceCount:string:)\n    @discardableResult\n    public func faceCount(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .faceCount, operatorString: operatorString, inputValue: object)\n    }\n    @objc(faceCount:expression:)\n    @discardableResult\n    public func faceCount(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .faceCount, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(faceCount:conditionExpression:)\n    @discardableResult\n    public func faceCount(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .faceCount, operatorString: operatorString, inputValue: object.asString())\n    }\n\n    @objc(tags:intValue:)\n    @discardableResult\n    public func tags(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .tags, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(tags:floatValue:)\n    @discardableResult\n    public func tags(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .tags, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(tags:string:)\n    @discardableResult\n    public func tags(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .tags, operatorString: operatorString, inputValue: object)\n    }\n    @objc(tags:expression:)\n    @discardableResult\n    public func tags(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .tags, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(tags:conditionExpression:)\n    @discardableResult\n    public func tags(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .tags, operatorString: operatorString, inputValue: object.asString())\n    }\n\n    @objc(pageXOffset:intValue:)\n    @discardableResult\n    public func pageXOffset(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .pageX, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(pageXOffset:floatValue:)\n    @discardableResult\n    public func pageXOffset(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .pageX, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(pageXOffset:string:)\n    @discardableResult\n    public func pageXOffset(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .pageX, operatorString: operatorString, inputValue: object)\n    }\n    @objc(pageXOffset:expression:)\n    @discardableResult\n    public func pageXOffset(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .pageX, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(pageXOffset:conditionExpression:)\n    @discardableResult\n    public func pageXOffset(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .pageX, operatorString: operatorString, inputValue: object.asString())\n    }\n\n    @objc(pageYOffset:intValue:)\n    @discardableResult\n    public func pageYOffset(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .pageY, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(pageYOffset:floatValue:)\n    @discardableResult\n    public func pageYOffset(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .pageY, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(pageYOffset:string:)\n    @discardableResult\n    public func pageYOffset(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .pageY, operatorString: operatorString, inputValue: object)\n    }\n    @objc(pageYOffset:expression:)\n    @discardableResult\n    public func pageYOffset(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .pageY, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(pageYOffset:conditionExpression:)\n    @discardableResult\n    public func pageYOffset(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .pageY, operatorString: operatorString, inputValue: object.asString())\n    }\n    \n    @objc(illustrationScore:intValue:)\n    @discardableResult\n    public func illustrationScore(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .illustrationScore, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(illustrationScore:floatValue:)\n    @discardableResult\n    public func illustrationScore(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .illustrationScore, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(illustrationScore:string:)\n    @discardableResult\n    public func illustrationScore(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .illustrationScore, operatorString: operatorString, inputValue: object)\n    }\n    @objc(illustrationScore:expression:)\n    @discardableResult\n    public func illustrationScore(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .illustrationScore, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(illustrationScore:conditionExpression:)\n    @discardableResult\n    public func illustrationScore(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .illustrationScore, operatorString: operatorString, inputValue: object.asString())\n    }\n    \n    @objc(currentPageIndex:intValue:)\n    @discardableResult\n    public func currentPageIndex(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .currentPage, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(currentPageIndex:floatValue:)\n    @discardableResult\n    public func currentPageIndex(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .currentPage, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(currentPageIndex:string:)\n    @discardableResult\n    public func currentPageIndex(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .currentPage, operatorString: operatorString, inputValue: object)\n    }\n    @objc(currentPageIndex:expression:)\n    @discardableResult\n    public func currentPageIndex(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .currentPage, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(currentPageIndex:conditionExpression:)\n    @discardableResult\n    public func currentPageIndex(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .currentPage, operatorString: operatorString, inputValue: object.asString())\n    }\n    \n    @objc(duration:intValue:)\n    @discardableResult\n    public func duration(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .duration, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(duration:floatValue:)\n    @discardableResult\n    public func duration(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .duration, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(duration:string:)\n    @discardableResult\n    public func duration(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .duration, operatorString: operatorString, inputValue: object)\n    }\n    @objc(duration:expression:)\n    @discardableResult\n    public func duration(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .duration, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(duration:conditionExpression:)\n    @discardableResult\n    public func duration(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .duration, operatorString: operatorString, inputValue: object.asString())\n    }\n    \n    @objc(initialDuration:intValue:)\n    @discardableResult\n    public func initialDuration(_ operatorString: String, _ object: Int) -> Self {\n        return predicate(expressionKey: .initialDuration, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(initialDuration:floatValue:)\n    @discardableResult\n    public func initialDuration(_ operatorString: String, _ object: Float) -> Self {\n        return predicate(expressionKey: .initialDuration, operatorString: operatorString, inputValue: String(object))\n    }\n    @objc(initialDuration:string:)\n    @discardableResult\n    public func initialDuration(_ operatorString: String, _ object: String) -> Self {\n        return predicate(expressionKey: .initialDuration, operatorString: operatorString, inputValue: object)\n    }\n    @objc(initialDuration:expression:)\n    @discardableResult\n    public func initialDuration(_ operatorString: String, _ object: CLDExpression) -> Self {\n        return predicate(expressionKey: .initialDuration, operatorString: operatorString, inputValue: object.asInternalString())\n    }\n    @objc(initialDuration:conditionExpression:)\n    @discardableResult\n    public func initialDuration(_ operatorString: String, _ object: CLDConditionExpression) -> Self {\n        return predicate(expressionKey: .initialDuration, operatorString: operatorString, inputValue: object.asString())\n    }\n    \n    // MARK: - Private Methods\n    private func appendingStringToCurrentValue(cldoperator: CLDOperators, inputValue: String) {\n        \n        let expression = CLDExpression.init(value: inputValue)\n        \n        let value: String\n        if  expression.currentValue.isEmpty {\n\n            value = inputValue\n        } else {\n         \n            value = expression.asString()\n        }\n        \n        appendOperatorToCurrentValue(cldoperator, inputValue: value)\n    }\n    \n    fileprivate func predicate(expressionKey: ExpressionKeys, operatorString: String, inputValue: String) -> Self {\n        let stringPredicate = \"\\(expressionKey.asString) \\(operatorString) \\(inputValue)\"\n        return value(stringPredicate)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/CLDDefinitions.swift",
    "content": "//\n//  CLDDefinitions.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n// MARK: URL Type\n\n@objc public enum CLDType: Int, CustomStringConvertible {\n    case upload, fetch, facebook, twitter, twitterName, sprite, `private`, authenticated\n    \n    public var description: String {\n        get {\n            switch self {\n            case .upload:               return \"upload\"\n            case .facebook:             return \"facebook\"\n            case .fetch:                return \"fetch\"\n            case .twitter:              return \"twitter\"\n            case .twitterName:          return \"twitter_name\"\n            case .sprite:               return \"sprite\"\n            case .private:              return \"private\"\n            case .authenticated:        return \"authenticated\"\n            }\n        }\n    }\n}\n\n// MARK: Resource Type\n\n@objc public enum CLDUrlResourceType: Int, CustomStringConvertible {\n    case image, raw, video, auto\n    \n    public var description: String {\n        get {\n            switch self {\n            case .image:        return \"image\"\n            case .raw:          return \"raw\"\n            case .video:        return \"video\"\n            case .auto:         return \"auto\"\n            }\n        }\n    }\n}\n\n// MARK: - Upload Params\n\n@objc public enum CLDModeration: Int, CustomStringConvertible {\n    case manual, webpurify\n    \n    public var description: String {\n        get {\n            switch self {\n            case .manual:           return \"manual\"\n            case .webpurify:        return \"webpurify\"\n            }\n        }\n    }\n}\n\n// MARK: - Text Params\n\n@objc public enum CLDFontWeight: Int, CustomStringConvertible {\n    case normal, bold\n    \n    public var description: String {\n        get {\n            switch self {\n            case .normal:           return \"normal\"\n            case .bold:             return \"bold\"\n            }\n        }\n    }\n}\n\n@objc public enum CLDFontStyle: Int, CustomStringConvertible {\n    case normal, italic\n    \n    public var description: String {\n        get {\n            switch self {\n            case .normal:           return \"normal\"\n            case .italic:           return \"italic\"\n            }\n        }\n    }\n}\n\n@objc public enum CLDTextDecoration: Int, CustomStringConvertible {\n    case none, underline\n    \n    public var description: String {\n        get {\n            switch self {\n            case .none:             return \"none\"\n            case .underline:        return \"underline\"\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/CLDExpression.swift",
    "content": "//\n//  CLDExpression.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDExpression: NSObject {\n\n    internal enum ExpressionKeys : String, CaseIterable {\n        \n        case width\n        case height\n        \n        case initial_width\n        case initialWidth\n        case initial_height\n        case initialHeight\n        \n        case initial_aspect_ratio\n        case aspect_ratio\n        case aspectRatio\n        case initialAspectRatio\n        \n        case page_count\n        case pageCount\n        \n        case face_count\n        case faceCount\n        \n        case illustration_score\n        case illustrationScore\n        \n        case current_page\n        case currentPage\n        \n        case tags\n        \n        case pageX\n        case pageY\n        case duration\n        \n        case initial_duration\n        case initialDuration\n        \n        var asString: String {\n            \n            switch self {\n            case .width : return \"w\"\n            case .height: return \"h\"\n                \n            case .initial_width : return \"iw\"\n            case .initialWidth  : return \"iw\"\n            case .initial_height: return \"ih\"\n            case .initialHeight : return \"ih\"\n                \n            case .initial_aspect_ratio: return \"iar\"\n            case .aspect_ratio        : return \"ar\"\n            case .aspectRatio         : return \"ar\"\n            case .initialAspectRatio  : return \"iar\"\n                \n            case .page_count: return \"pc\"\n            case .pageCount : return \"pc\"\n                \n            case .face_count: return \"fc\"\n            case .faceCount : return \"fc\"\n                \n            case .illustration_score: return \"ils\"\n            case .illustrationScore : return \"ils\"\n                \n            case .current_page: return \"cp\"\n            case .currentPage : return \"cp\"\n                \n            case .tags: return \"tags\"\n            \n            case .pageX: return \"px\"\n            case .pageY: return \"py\"\n                \n            case .duration: return \"du\"\n            case .initial_duration: return \"idu\"\n            case .initialDuration : return \"idu\"\n            }\n        }\n    }\n    \n    internal var currentValue      : String\n    internal var currentKey        : String\n    \n    private var allSpaceAndOrDash       : Bool = false\n    private let consecutiveDashesRegex  : String = \"[ _]+\"\n    private let userVariableRegex       : String = \"\\\\$_*[^_]+\"\n    \n    // MARK: - Init\n    public override init() {\n        self.currentKey   = String()\n        self.currentValue = String()\n        super.init()\n    }\n    \n    public init(value: String) {\n        var components = value.components(separatedBy: .whitespacesAndNewlines)\n        self.currentKey   = components.removeFirst()\n        self.currentValue = components.joined(separator: CLDVariable.elementsSeparator)\n        let range = NSRange(location: 0, length: value.utf16.count)\n        let regex = try? NSRegularExpression(pattern: \"^\" + consecutiveDashesRegex)\n        self.allSpaceAndOrDash = !(regex?.firstMatch(in: value, options: [], range: range) == nil)\n        super.init()\n    }\n    \n    fileprivate init(expressionKey: ExpressionKeys) {\n        self.currentKey   = expressionKey.asString\n        self.currentValue = String()\n        super.init()\n    }\n    \n    // MARK: - class func\n    public class func width() -> CLDExpression {\n        return CLDExpression(expressionKey: .width)\n    }\n    \n    public class func height() -> CLDExpression {\n        return CLDExpression(expressionKey: .height)\n    }\n    \n    public class func initialWidth() -> CLDExpression {\n        return CLDExpression(expressionKey: .initialWidth)\n    }\n    \n    public class func initialHeight() -> CLDExpression {\n        return CLDExpression(expressionKey: .initialHeight)\n    }\n    \n    public class func aspectRatio() -> CLDExpression {\n        return CLDExpression(expressionKey: .aspectRatio)\n    }\n    \n    public class func initialAspectRatio() -> CLDExpression {\n        return CLDExpression(expressionKey: .initialAspectRatio)\n    }\n    \n    public class func pageCount() -> CLDExpression {\n        return CLDExpression(expressionKey: .pageCount)\n    }\n    \n    public class func faceCount() -> CLDExpression {\n        return CLDExpression(expressionKey: .faceCount)\n    }\n    \n    public class func tags() -> CLDExpression {\n        return CLDExpression(expressionKey: .tags)\n    }\n    \n    public class func pageXOffset() -> CLDExpression {\n        return CLDExpression(expressionKey: .pageX)\n    }\n    \n    public class func pageYOffset() -> CLDExpression {\n        return CLDExpression(expressionKey: .pageY)\n    }\n    \n    public class func illustrationScore() -> CLDExpression {\n        return CLDExpression(expressionKey: .illustrationScore)\n    }\n    \n    public class func currentPageIndex() -> CLDExpression {\n        return CLDExpression(expressionKey: .currentPage)\n    }\n    \n    public class func duration() -> CLDExpression {\n        return CLDExpression(expressionKey: .duration)\n    }\n    public class func initialDuration() -> CLDExpression {\n        return CLDExpression(expressionKey: .initialDuration)\n    }\n    \n    // MARK: - Public methods\n    @objc(addByInt:)\n    @discardableResult\n    public func add(by number: Int) -> Self {\n        appendOperatorToCurrentValue(.add, inputValue: \"\\(number)\")\n        return self\n    }\n    @objc(addByFloat:)\n    @discardableResult\n    public func add(by number: Float) -> Self {\n        appendOperatorToCurrentValue(.add, inputValue: number.cldFloatFormat())\n        return self\n    }\n    @objc(addByString:)\n    @discardableResult\n    public func add(by number: String) -> Self {\n        appendOperatorToCurrentValue(.add, inputValue: number)\n        return self\n    }\n    \n    @objc(subtractByInt:)\n    @discardableResult\n    public func subtract(by number: Int) -> Self {\n        appendOperatorToCurrentValue(.subtract, inputValue: \"\\(number)\")\n        return self\n    }\n    @objc(subtractByFloat:)\n    @discardableResult\n    public func subtract(by number: Float) -> Self {\n        appendOperatorToCurrentValue(.subtract, inputValue: number.cldFloatFormat())\n        return self\n    }\n    @objc(subtractByString:)\n    @discardableResult\n    public func subtract(by number: String) -> Self {\n        appendOperatorToCurrentValue(.subtract, inputValue: number)\n        return self\n    }\n    \n    @objc(multipleByInt:)\n    @discardableResult\n    public func multiple(by number: Int) -> Self {\n        appendOperatorToCurrentValue(.multiple, inputValue: \"\\(number)\")\n        return self\n    }\n    @objc(multipleByFloat:)\n    @discardableResult\n    public func multiple(by number: Float) -> Self {\n        appendOperatorToCurrentValue(.multiple, inputValue: number.cldFloatFormat())\n        return self\n    }\n    @objc(multipleByString:)\n    @discardableResult\n    public func multiple(by number: String) -> Self {\n        appendOperatorToCurrentValue(.multiple, inputValue: number)\n        return self\n    }\n    \n    @objc(divideByInt:)\n    @discardableResult\n    public func divide(by number: Int) -> Self {\n        appendOperatorToCurrentValue(.divide, inputValue: \"\\(number)\")\n        return self\n    }\n    @objc(divideByFloat:)\n    @discardableResult\n    public func divide(by number: Float) -> Self {\n        appendOperatorToCurrentValue(.divide, inputValue: number.cldFloatFormat())\n        return self\n    }\n    @objc(divideByString:)\n    @discardableResult\n    public func divide(by number: String) -> Self {\n        appendOperatorToCurrentValue(.divide, inputValue: number)\n        return self\n    }\n    \n    @objc(powerByInt:)\n    @discardableResult\n    public func power(by number: Int) -> Self {\n        appendOperatorToCurrentValue(.power, inputValue: \"\\(number)\")\n        return self\n    }\n    @objc(powerByFloat:)\n    @discardableResult\n    public func power(by number: Float) -> Self {\n        appendOperatorToCurrentValue(.power, inputValue: number.cldFloatFormat())\n        return self\n    }\n    @objc(powerByString:)\n    @discardableResult\n    public func power(by number: String) -> Self {\n        appendOperatorToCurrentValue(.power, inputValue: number)\n        return self\n    }\n    \n    // MARK: - provide content\n    public func asString() -> String {\n        \n        guard !currentKey.isEmpty else {\n            if allSpaceAndOrDash {\n                return \"_\"\n            }\n            return String()\n        }\n        \n        let key = removeExtraDashes(from: replaceAllExpressionKeys(in: currentKey))\n\n        if currentValue.isEmpty {\n            return \"\\(key)\"\n        }\n        \n        let value = removeExtraDashes(from: replaceAllUnencodeChars(in: currentValue))\n        return \"\\(key)_\\(value)\"\n    }\n    \n    public func asParams() -> [String : String] {\n        \n        guard !currentKey.isEmpty && !currentValue.isEmpty else {\n            \n            return [String : String]()\n        }\n        \n        let key   = replaceAllExpressionKeys(in: currentKey)\n        let value = removeExtraDashes(from: replaceAllUnencodeChars(in: currentValue))\n        \n        return [key:value]\n    }\n    \n    internal func asInternalString() -> String {\n\n        guard !currentValue.isEmpty else {\n        \n            return \"\\(currentKey)\"\n        }\n        return \"\\(currentKey) \\(currentValue)\"\n    }\n    \n    // MARK: - Private methods\n    private func replaceAllUnencodeChars(in string: String) -> String {\n        \n        var wipString   = string\n        wipString       = replaceAllOperators(in: string)\n        wipString       = replaceAllExpressionKeys(in: wipString)\n        return wipString\n    }\n    \n    private func replaceAllOperators(in string: String) -> String {\n        \n        var wipString = string\n        CLDOperators.allCases.forEach {\n                wipString = replace(cldOperator: $0, in: wipString)\n        }\n        \n        return wipString\n    }\n    \n    private func replace(cldOperator: CLDOperators, in string: String) -> String {\n        \n        return string.replacingOccurrences(of: cldOperator.rawValue, with: cldOperator.asString())\n    }\n    \n    private func replaceAllExpressionKeys(in string: String) -> String {\n        \n        var wipString = string\n        ExpressionKeys.allCases.forEach {\n                \n            wipString = replace(expressionKey: $0, in: wipString)\n        }\n        \n        return wipString\n    }\n    \n    private func replace(expressionKey: ExpressionKeys, in string: String) -> String {\n\n        var result : String!\n        let string = removeExtraDashes(from: string)\n\n        if string.contains(CLDVariable.variableNamePrefix) {\n            let range = NSRange(location: 0, length: string.utf16.count)\n            let regex = try? NSRegularExpression(pattern: userVariableRegex)\n            let allRanges = regex?.matches(in: string, options: [], range: range).map({ $0.range }) ?? []\n\n            // Replace substring in between user variables. e.x $initial_aspect_ratio_$width, only '_aspect_ratio_' will be addressed.\n            for (index, range) in allRanges.enumerated() {\n                let location = range.length + range.location\n                var length = range.length\n\n                if index + 1 == allRanges.count {\n                    length = string.count\n                } else {\n                    let nextRange = allRanges[index + 1]\n                    length = nextRange.location\n                }\n\n                if let stringRange = Range(NSRange(location: location, length: length - location), in: string) {\n                    result = string.replacingOccurrences(of: expressionKey.rawValue, with: expressionKey.asString, options: .regularExpression, range: stringRange)\n                }\n            }\n        } else {\n            result = string.replacingOccurrences(of: expressionKey.rawValue, with: expressionKey.asString)\n        }\n        return result\n    }\n    \n    internal func appendOperatorToCurrentValue(_ cldoperator: CLDOperators, inputValue: String = String()) {\n        appendOperatorToCurrentValue(cldoperator.asString(), inputValue: inputValue)\n    }\n    \n    internal func appendOperatorToCurrentValue(_ cldoperator: String, inputValue: String = String()) {\n        \n        var stringValue = String()\n        if !currentValue.isEmpty {\n           \n            stringValue.append(CLDVariable.elementsSeparator)\n        }\n        \n        stringValue.append(cldoperator)\n        \n        if !inputValue.isEmpty {\n         \n            stringValue.append(CLDVariable.elementsSeparator + inputValue)\n        }\n        \n        currentValue.append(stringValue)\n    }\n    \n    private func removeExtraDashes(from string: String) -> String {\n        return string.replacingOccurrences(of: consecutiveDashesRegex, with: CLDVariable.elementsSeparator, options: .regularExpression, range: nil)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/CLDOperators.swift",
    "content": "//\n//  CLDOperators.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\npublic enum CLDOperators: String , CaseIterable {\n    \n    case and = \"&&\"\n    case or  = \"||\"\n    \n    case multiple = \"*\"\n    case divide   = \"/\"\n    case add      = \"+\"\n    case subtract = \"-\"\n\n    case power    = \"^\"\n    \n    case notInside      = \"notInside\"\n    case inside         = \"inside\"\n    \n    case lessOrEqual    = \"<=\"\n    case greaterOrEqual = \">=\"\n    case lessThen       = \"<\"\n    case greaterThen    = \">\"\n    case notEqual       = \"!=\"\n    case equal          = \"=\"\n    \n    func asString() -> String {\n        \n        switch self {\n        case .equal         : return \"eq\"\n        case .notEqual      : return \"ne\"\n        case .lessThen      : return \"lt\"\n        case .greaterThen   : return \"gt\"\n        case .lessOrEqual   : return \"lte\"\n        case .greaterOrEqual: return \"gte\"\n        case .inside        : return \"in\"\n        case .notInside     : return \"nin\"\n\n        case .and: return \"and\"\n        case .or : return \"or\"\n\n        case .multiple: return \"mul\"\n        case .divide  : return \"div\"\n        case .add     : return \"add\"\n        case .subtract: return \"sub\"\n        case .power   : return \"pow\"\n        }\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/CLDTransformation.swift",
    "content": "//\n//  CLDTransformation.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport CoreGraphics\n/**\n The CLDTransformation class represents a full transformation performed by Cloudinay on-the-fly on a certain asset.\n */\n@objcMembers open class CLDTransformation: NSObject {\n    \n    fileprivate typealias Transformation = [String : String]\n    \n    static fileprivate let transformationContentSeparator: String = \",\"\n    static fileprivate let elementsSeparator             : String = \"_\"\n    \n    fileprivate var currentTransformationParams: Transformation\n    fileprivate var transformations : [Transformation]\n    fileprivate var currentCondition: CLDConditionExpression?\n    \n    // MARK: - Init\n    \n    public override init() {\n        self.currentTransformationParams =  Transformation()\n        self.transformations             = [Transformation]()\n        self.currentCondition            = nil\n        super.init()\n    }\n    \n    public init(input: [CLDTransformation]) {\n        \n        self.currentTransformationParams =  Transformation()\n        self.transformations             = [Transformation]()\n        self.currentCondition            = nil\n        \n        super.init()\n        \n        input.forEach {\n            $0.chain()\n            transformations.append(contentsOf: $0.transformations)\n        }\n    }\n    \n    // MARK: - Get Values\n    \n    open var width: String? {\n        return getParam(.WIDTH)\n    }\n    \n    open var height: String? {\n        return getParam(.HEIGHT)\n    }\n    \n    open var named: String? {\n        return getParam(.NAMED)\n    }\n    \n    open var crop: String? {\n        return getParam(.CROP)\n    }\n    \n    open var background: String? {\n        return getParam(.BACKGROUND)\n    }\n    \n    open var color: String? {\n        return getParam(.COLOR)\n    }\n    \n    open var effect: String? {\n        return getParam(.EFFECT)\n    }\n    \n    open var angle: String? {\n        return getParam(.ANGLE)\n    }\n    \n    open var opacity: String? {\n        return getParam(.OPACITY)\n    }\n    \n    open var border: String? {\n        return getParam(.BORDER)\n    }\n    \n    open var x: String? {\n        return getParam(.X)\n    }\n    \n    open var y: String? {\n        return getParam(.Y)\n    }\n    \n    open var radius: String? {\n        return getParam(.RADIUS)\n    }\n    \n    open var quality: String? {\n        return getParam(.QUALITY)\n    }\n    \n    open var defaultImage: String? {\n        return getParam(.DEFAULT_IMAGE)\n    }\n    \n    open var gravity: String? {\n        return getParam(.GRAVITY)\n    }\n    \n    open var colorSpace: String? {\n        return getParam(.COLOR_SPACE)\n    }\n    \n    open var prefix: String? {\n        return getParam(.PREFIX)\n    }\n    \n    open var overlay: String? {\n        return getParam(.OVERLAY)\n    }\n    \n    open var underlay: String? {\n        return getParam(.UNDERLAY)\n    }\n    \n    open var fetchFormat: String? {\n        return getParam(.FETCH_FORMAT)\n    }\n    \n    open var density: String? {\n        return getParam(.DENSITY)\n    }\n    \n    open var page: String? {\n        return getParam(.PAGE)\n    }\n    \n    open var delay: String? {\n        return getParam(.DELAY)\n    }\n    \n    open var rawTransformation: String? {\n        return getParam(.RAW_TRANSFORMATION)\n    }\n    \n    open var variables: String? {\n        return getParam(.VARIABLES)\n    }\n    \n    open var ifParam: String? {\n        return getParam(.IF_PARAM)\n    }\n    \n    open var flags: String? {\n        return getParam(.FLAGS)\n    }\n    \n    open var dpr: String? {\n        return getParam(.DPR)\n    }\n    \n    open var zoom: String? {\n        return getParam(.ZOOM)\n    }\n    \n    open var aspectRatio: String? {\n        return getParam(.ASPECT_RATIO)\n    }\n    \n    open var customPreFunction: String? {\n        guard let base = getParam(.CUSTOM_FUNCTION) else { return nil }\n        return base.removePrefix(\"pre:\")\n    }\n    \n    open var customFunction: String? {\n        return getParam(.CUSTOM_FUNCTION)\n    }\n    \n    open var audioCodec: String? {\n        return getParam(.AUDIO_CODEC)\n    }\n    \n    open var audioFrequency: String? {\n        return getParam(.AUDIO_FREQUENCY)\n    }\n    \n    open var bitRate: String? {\n        return getParam(.BIT_RATE)\n    }\n    \n    open var videoSampling: String? {\n        return getParam(.VIDEO_SAMPLING)\n    }\n    \n    open var duration: String? {\n        return getParam(.DURATION)\n    }\n    \n    open var startOffset: String? {\n        return getParam(.START_OFFSET)\n    }\n    \n    open var endOffset: String? {\n        return getParam(.END_OFFSET)\n    }\n    \n    open var offset: [String]? {\n        guard let\n            start = startOffset,\n            let end = endOffset else {\n                return nil\n        }\n        return [start, end]\n    }\n    \n    open var videoCodec: String? {\n        return getParam(.VIDEO_CODEC)\n    }\n    \n    open var fps: String? {\n        return getParam(.FPS)\n    }\n    \n    open var keyframeInterval: String? {\n        return getParam(.KEYFRAME_INTERVAL)\n    }\n    \n    open var streamingProfile: String? {\n        return getParam(.STREAMING_PROFILE)\n    }\n    \n    fileprivate func getParam(_ param: TransformationParam) -> String? {\n        return getParam(param.rawValue)\n    }\n    \n    open func getParam(_ param: String) -> String? {\n        return currentTransformationParams[param]\n    }\n    \n    // MARK: - Set Values - Variable\n    \n    /**\n     Set a variable.\n     \n     - parameter name:       The variable's name.\n     - parameter value:      The variable's value.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @objc(setVariable:intValue:)\n    @discardableResult\n    public func setVariable(_ name: String, int value: Int) -> Self {\n        \n        let variable = CLDVariable(name: name, value: String(value))\n        return setVariable(variable)\n    }\n    /**\n     Set a variable.\n     \n     - parameter name:       The variable's name.\n     - parameter value:      The variable's value.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @objc(setVariable:floatValue:)\n    @discardableResult\n    public func setVariable(_ name: String, float value: Float) -> Self {\n        \n        let variable = CLDVariable(name: name, value: value.cldFloatFormat())\n        return setVariable(variable)\n    }\n    /**\n     Set a variable.\n     \n     - parameter name:       The variable's name.\n     - parameter value:      The variable's value.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @objc(setVariable:string:)\n    @discardableResult\n    public func setVariable(_ name: String, string value: String) -> Self {\n        \n        let variable = CLDVariable(name: name, value: value)\n        return setVariable(variable)\n    }\n    /**\n     Set a variable.\n     \n     - parameter name:       The variable's name.\n     - parameter values:      The variable's value.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @objc(setVariable:valuesArray:)\n    @discardableResult\n    public func setVariable(_ name: String, values: [String]) -> Self {\n        \n        let variable = CLDVariable(name: name, values: values)\n        return setVariable(variable)\n    }\n    \n    /**\n     Set a variable.\n     \n     - parameter variable:   The variable to set.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @objc(setVariableWithVariable:)\n    @discardableResult\n    public func setVariable(_ variable: CLDVariable) -> Self {\n        \n        guard variable.isValid else { return self }\n        \n        return setParam(variable.name, value: variable.value)\n    }\n    \n    /**\n     Set an array of variables.\n     \n     - parameter variables:  The variables to set.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @objc(setVariablesWithVariablesArray:)\n    @discardableResult\n    public func setVariables(_ variables: [CLDVariable]) -> Self {\n        \n        let joined = variables.filter {\n            $0.isValid\n        }.map {\n            $0.asString()\n        }.joined(separator: CLDTransformation.transformationContentSeparator)\n        \n        setParam(TransformationParam.VARIABLES.rawValue, value: joined)\n        \n        return self\n    }\n    \n    // MARK: - Set Values - Width\n    /**\n     Set the image width.\n     \n     - parameter width:      The width to set.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @objc(setWidthWithInt:)\n    @discardableResult\n    open func setWidth(_ width: Int) -> Self {\n        return setWidth(String(width))\n    }\n    \n    /**\n     Set the image width.\n     \n     - parameter width:      The width to set.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @objc(setWidthWithFloat:)\n    @discardableResult\n    open func setWidth(_ width: Float) -> Self {\n        return setWidth(width.cldFloatFormat())\n    }\n    \n    /**\n     Set the image width.\n     \n     - parameter width:      The width to set.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setWidth(_ width: String) -> Self {\n        \n        return setParam(TransformationParam.WIDTH, expression: CLDExpression(value: width), fallback: width)\n    }\n    \n    // MARK: - Set Values - Height\n    /**\n     Set the image height.\n     \n     - parameter height:     The height to set.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @objc(setHeightWithInt:)\n    @discardableResult\n    open func setHeight(_ height: Int) -> Self {\n        return setHeight(String(height))\n    }\n    \n    /**\n     Set the image height.\n     \n     - parameter height:     The height to set.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @objc(setHeightWithFloat:)\n    @discardableResult\n    open func setHeight(_ height: Float) -> Self {\n        return setHeight(height.cldFloatFormat())\n    }\n    \n    /**\n     Set the image height.\n     \n     - parameter height:     The height to set.\n     \n     - returns:              The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setHeight(_ height: String) -> Self {\n        \n        return setParam(TransformationParam.HEIGHT, expression: CLDExpression(value: height), fallback: height)\n    }\n    \n    // MARK: - Set Values - Named\n    \n    /**\n     A named transformation is a set of image transformations that has been given a custom name for easy reference.\n     It is useful to define a named transformation when you have a set of relatively complex transformations that you use often and that you want to easily reference.\n     \n     - parameter names:     The names of the transformations to set.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setNamedWithArray:)\n    @discardableResult\n    open func setNamed(_ names: [String]) -> Self {\n        return setNamed(names.joined(separator: \".\"))\n    }\n    \n    /**\n     A named transformation is a set of image transformations that has been given a custom name for easy reference.\n     It is useful to define a named transformation when you have a set of relatively complex transformations that you use often and that you want to easily reference.\n     \n     - parameter names:     The names of the transformations to set.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setNamed(_ names: String) -> Self {\n        return setParam(TransformationParam.NAMED, value: names)\n    }\n    \n    // MARK: - Set Values - Crop\n    \n    /**\n     Set the image crop.\n     \n     - parameter crop:      The crop to set.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setCropWithCrop:)\n    @discardableResult\n    open func setCrop(_ crop: CLDCrop) -> Self {\n        return setCrop(String(describing: crop))\n    }\n    \n    /**\n     Set the image crop.\n     \n     - parameter crop:      The crop to set.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setCrop(_ crop: String) -> Self {\n        return setParam(TransformationParam.CROP, value: crop)\n    }\n    \n    // MARK: - Set Values - Background\n    \n    /**\n     Defines the background color to use instead of transparent background areas when converting to JPG format or using the pad crop mode.\n     The background color can be set as an RGB hex triplet (e.g. '#3e2222'), a 3 character RGB hex (e.g. '#777') or a named color (e.g. 'green').\n     \n     - parameter background:    The background color to set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setBackground(_ background: String) -> Self {\n        return setParam(TransformationParam.BACKGROUND, value: background.replacingOccurrences(of: \"#\", with: \"rgb:\"))\n    }\n    \n    // MARK: - Set Values - Color\n    \n    /**\n     Customize the color to use together with: text captions, the shadow effect and the colorize effect.\n     The color can be set as an RGB hex triplet (e.g. '#3e2222'), a 3 character RGB hex (e.g. '#777') or a named color (e.g. 'green').\n     \n     - parameter color:     The color to set.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setColor(_ color: String) -> Self {\n        return setParam(TransformationParam.COLOR, value: color.replacingOccurrences(of: \"#\", with: \"rgb:\"))\n    }\n    \n    // MARK: - Set Values - Effect\n    \n    /**\n     Apply a filter or an effect on an image.\n     \n     - parameter effect:    The effect to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setEffectWithEffect:)\n    @discardableResult\n    open func setEffect(_ effect: CLDEffect) -> Self {\n        return setEffect(String(describing: effect))\n    }\n    \n    /**\n     Apply a filter or an effect on an image.\n     The value includes the name of the effect and an additional parameter that controls the behavior of the specific effect.\n     \n     - parameter effect:        The effect to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setEffectWithArtFilter:)\n    @discardableResult\n    open func setEffect(_ effect: CLDArtFilters) -> CLDTransformation {\n        return setEffect(.art, param: String(describing: effect))\n    }\n    \n    /**\n     Apply a filter or an effect on an image.\n     The value includes the name of the effect and an additional parameter that controls the behavior of the specific effect.\n     \n     - parameter effect:        The effect to apply.\n     - parameter param:   The effect value to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setEffectWithEffect:param:)\n    @discardableResult\n    open func setEffect(_ effect: CLDEffect, param: String) -> Self {\n        return setEffect(String(describing: effect), param: param)\n    }\n    \n    /**\n     Apply a filter or an effect on an image.\n     The value includes the name of the effect and an additional parameter that controls the behavior of the specific effect.\n     \n     - parameter effect:        The effect to apply.\n     - parameter param:   The effect value to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setEffect(_ effect: String, param: String) -> Self {\n        return setEffect(\"\\(effect):\\(param)\")\n    }\n    \n    /**\n     Apply a filter or an effect on an image.\n     \n     - parameter effect:    The effect to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setEffect(_ effect: String) -> Self {\n        return setParam(TransformationParam.EFFECT, value: effect)\n    }\n    \n    // MARK: - Set Values - Angle\n    \n    /**\n     Rotate or flip an image by the given degrees or automatically according to its orientation or available meta-data.\n     \n     - parameter angle:     The angle to rotate.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setAngleWithInt:)\n    @discardableResult\n    open func setAngle(_ angle: Int) -> Self {\n        return setAngle(String(angle))\n    }\n    \n    /**\n     Rotate or flip an image by the given degrees or automatically according to its orientation or available meta-data.\n     \n     - parameter angles:    The angles to rotate.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setAngleWithArray:)\n    @discardableResult\n    open func setAngle(_ angles: [String]) -> Self {\n        return setAngle(angles.joined(separator: \".\"))\n    }\n    \n    /**\n     Rotate or flip an image by the given degrees or automatically according to its orientation or available meta-data.\n     \n     - parameter angle:    The angle to rotate.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setAngle(_ angle: String) -> Self {\n        return setParam(TransformationParam.ANGLE, value: angle)\n    }\n    \n    // MARK: - Set Values - Opacity\n    \n    /**\n     Adjust the opacity of the image and make it semi-transparent. 100 means opaque, while 0 is completely transparent.\n     \n     - parameter opacity:   The opacity level to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setOpacityWithInt:)\n    @discardableResult\n    open func setOpacity(_ opacity: Int) -> Self {\n        return setOpacity(String(opacity))\n    }\n    \n    /**\n     Adjust the opacity of the image and make it semi-transparent. 100 means opaque, while 0 is completely transparent.\n     \n     - parameter opacity:   The opacity level to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setOpacity(_ opacity: String) -> Self {\n        return setParam(TransformationParam.OPACITY, value: opacity)\n    }\n    \n    // MARK: - Set Values - Border\n    \n    /**\n     Add a solid border around the image.\n     \n     - parameter width:     The border width.\n     - parameter color:     The border color.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setBorder(_ width: Int, color: String) -> Self {\n        return setBorder(\"\\(width)px_solid_\\(color)\")\n    }\n    \n    /**\n     Add a solid border around the image.\n     Should conform to the form: [width]px_solid_[color], e.g - 5px_solid_#111111 or 5px_solid_red\n     \n     - parameter border:     The border to add.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setBorder(_ border: String) -> Self {\n        return setParam(TransformationParam.BORDER, value: border.replacingOccurrences(of: \"#\", with: \"rgb:\"))\n    }\n    \n    // MARK: - Set Values - X\n    \n    /**\n     Horizontal position for custom-coordinates based cropping, overlay placement and certain region related effects.\n     \n     - parameter x:     The x position to add.\n     \n     - returns:         The same instance of CLDTransformation.\n     */\n    @objc(setXFromInt:)\n    @discardableResult\n    open func setX(_ x: Int) -> Self {\n        return setX(String(x))\n    }\n    \n    /**\n     Horizontal position for custom-coordinates based cropping, overlay placement and certain region related effects.\n     \n     - parameter x:     The x position to add.\n     \n     - returns:         The same instance of CLDTransformation.\n     */\n    @objc(setXFromFloat:)\n    @discardableResult\n    open func setX(_ x: Float) -> Self {\n        return setX(x.cldFloatFormat())\n    }\n    \n    /**\n     Horizontal position for custom-coordinates based cropping, overlay placement and certain region related effects.\n     \n     - parameter x:     The x position to add.\n     \n     - returns:         The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setX(_ x: String) -> Self {\n        \n        return setParam(TransformationParam.X, expression: CLDExpression(value: x), fallback: x)\n    }\n    \n    // MARK: - Set Values - Y\n    \n    /**\n     Vertical position for custom-coordinates based cropping and overlay placement.\n     \n     - parameter y:     The y position to add.\n     \n     - returns:         The same instance of CLDTransformation.\n     */\n    @objc(setYFromInt:)\n    @discardableResult\n    open func setY(_ y: Int) -> Self {\n        return setY(String(y))\n    }\n    \n    /**\n     Vertical position for custom-coordinates based cropping and overlay placement.\n     \n     - parameter y:     The y position to add.\n     \n     - returns:         The same instance of CLDTransformation.\n     */\n    @objc(setYFromFloat:)\n    @discardableResult\n    open func setY(_ y: Float) -> Self {\n        return setY(y.cldFloatFormat())\n    }\n    \n    /**\n     Vertical position for custom-coordinates based cropping and overlay placement.\n     \n     - parameter y:     The y position to add.\n     \n     - returns:         The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setY(_ y: String) -> Self {\n        return setParam(TransformationParam.Y, expression: CLDExpression(value: y), fallback: y)\n    }\n    \n    // MARK: - Set Values - Radius\n    \n    /**\n     Round the corners of an image or make it completely circular or oval (ellipse).\n     \n     - parameter radius:    The radius to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setRadiusFromInt:)\n    @discardableResult\n    open func setRadius(_ radius: Int) -> Self {\n        return setRadius(String(radius))\n    }\n    \n    /**\n     Round the corners of an image or make it completely circular or oval (ellipse).\n     \n     - parameter radius:    The radius to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setRadius(_ radius: String) -> Self {\n        \n        return setParam(TransformationParam.RADIUS, expression: CLDExpression(value: radius), fallback: radius)\n    }\n  \n   /**\n    Support an array value for radius\n     \n     - parameter radius:    - The radius to apply- an array of values\n     \n     - returns:             The same instance of CLDTransformation.\n    */\n\n   @objc(setRadiusFromArray:)\n   @discardableResult\n   open func setRadius(_ radius: [Any]) -> Self {\n       return setRadius(radius.map{String(describing: $0)}.joined(separator:\":\"))\n   }\n  \n   // MARK: - Set Values - Quality\n   /**\n    Set the image quality for the transformation, see CLDQuality for options.\n\n     - parameter quality:   A CLDQuality instance containing the quality settings.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setQualityFromQuality:)\n    @discardableResult\n    open func setQuality(_ quality: CLDQuality) -> Self {\n        return setQuality(quality.description)\n    }\n    \n    /**\n     Control the JPEG, WebP, GIF, JPEG XR and JPEG 2000 compression quality. 1 is the lowest quality and 100 is the highest. Reducing quality generates JPG images much smaller in file size. The default values are:\n     * JPEG: 90\n     * WebP: 80 (100 quality for WebP is lossless)\n     * GIF: lossless by default. 80 if the `lossy` flag is added\n     * JPEG XR and JPEG 2000: 70\n     \n     - parameter quality:   The quality to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setQualityFromInt:)\n    @discardableResult\n    @available(*, deprecated, message: \"Use setQuality(CLDQuality)\")\n    open func setQuality(_ quality: Int) -> Self {\n        return setQuality(String(quality))\n    }\n    \n    /**\n     Control the JPEG, WebP, GIF, JPEG XR and JPEG 2000 compression quality. 1 is the lowest quality and 100 is the highest. Reducing quality generates JPG images much smaller in file size. The default values are:\n     * JPEG: 90\n     * WebP: 80 (100 quality for WebP is lossless)\n     * GIF: lossless by default. 80 if the `lossy` flag is added\n     * JPEG XR and JPEG 2000: 70\n     \n     - parameter quality:   The quality to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setQuality(_ quality: String) -> Self {\n        return setParam(TransformationParam.QUALITY, value: quality)\n    }\n    \n    // MARK: - Set Values - DefaultImage\n    \n    /**\n     Specify the public ID of a placeholder image to use if the requested image or social network picture does not exist.\n     \n     - parameter defaultImage:      The identifier of the default image.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setDefaultImage(_ defaultImage: String) -> Self {\n        return setParam(TransformationParam.DEFAULT_IMAGE, value: defaultImage)\n    }\n    \n    // MARK: - Set Values - Gravity\n    \n    /**\n     Decides which part of the image to keep while 'crop', 'pad' and 'fill' crop modes are used.\n     \n     - parameter gravity:           The gravity to apply.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @objc(setGravityWithGravity:)\n    @discardableResult\n    open func setGravity(_ gravity: CLDGravity) -> Self {\n        return setGravity(String(describing: gravity))\n    }\n    \n    /**\n     Decides which part of the image to keep while 'crop', 'pad' and 'fill' crop modes are used.\n     \n     - parameter gravity:           The gravity to apply.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setGravity(_ gravity: String) -> Self {\n        return setParam(TransformationParam.GRAVITY, value: gravity)\n    }\n    // MARK: - Set Values - ColorSpace\n    /**\n     Set the transformation color space.\n     \n     - parameter colorSpace:        The color space to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setColorSpace(_ colorSpace: String) -> Self {\n        return setParam(TransformationParam.COLOR_SPACE, value: colorSpace)\n    }\n    // MARK: - Set Values - Prefix\n    /**\n     Set the transformation prefix.\n     \n     - parameter prefix:            The prefix to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setPrefix(_ prefix: String) -> Self {\n        return setParam(TransformationParam.PREFIX, value: prefix)\n    }\n    // MARK: - Set Values - Overlay\n    /**\n     Add an overlay over the base image. You can control the dimension and position of the overlay using the width, height, x, y and gravity parameters.\n     The overlay can take one of the following forms:\n     identifier can be a public ID of an uploaded image or a specific image kind, public ID and settings.\n     \n     **You can use the convenience method `addOverlayWithLayer`**\n     \n     - parameter overlay:           The overlay to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setOverlay(_ overlay: String) -> Self {\n        return setParam(TransformationParam.OVERLAY, value: overlay)\n    }\n    // MARK: - Set Values - Underlay\n    /**\n     Add an underlay image below a base partially-transparent image.\n     You can control the dimensions and position of the underlay using the width, height, x, y and gravity parameters.\n     The identifier can be a public ID of an uploaded image or a specific image kind, public ID and settings.\n     The underlay parameter shares the same features as the overlay parameter.\n     \n     **You can use the convenience method `addUnderlayWithLayer`**\n     \n     - parameter underlay:          The underlay to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setUnderlay(_ underlay: String) -> Self {\n        return setParam(TransformationParam.UNDERLAY, value: underlay)\n    }\n    // MARK: - Set Values - FetchFormat\n    \n    /**\n     Force format conversion to the given image format for remote 'fetch' URLs and auto uploaded images that already have a different format as part of their URLs.\n     \n     - parameter fetchFormat:       The fetchFormat to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setFetchFormat(_ fetchFormat: String) -> Self {\n        return setParam(TransformationParam.FETCH_FORMAT, value: fetchFormat)\n    }\n    \n    // MARK: - Set Values - Density\n    \n    /**\n     Control the density to use while converting a PDF document to images. (range: 50-300, default is 150)\n     \n     - parameter density:           The density to use.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @objc(setDensityWithInt:)\n    @discardableResult\n    open func setDensity(_ density: Int) -> Self {\n        return setDensity(String(density))\n    }\n    \n    /**\n     Control the density to use while converting a PDF document to images. (range: 50-300, default is 150)\n     \n     - parameter density:           The density to use.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setDensity(_ density: String) -> Self {\n        return setParam(TransformationParam.DENSITY, value: density)\n    }\n    // MARK: - Set Values - Page\n    /**\n     Given a multi-page file (PDF, animated GIF, TIFF), generate an image of a single page using the given index.\n     \n     - parameter page:              The index of the page to use to use.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @objc(setPageWithInt:)\n    @discardableResult\n    open func setPage(_ page: Int) -> Self {\n        return setPage(String(page))\n    }\n    \n    /**\n     Given a multi-page file (PDF, animated GIF, TIFF), generate an image of a single page using the given index.\n     \n     - parameter page:              The index of the page to use to use.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setPage(_ page: String) -> Self {\n        return setParam(TransformationParam.PAGE, value: page)\n    }\n    \n    // MARK: - Set Values - Delay\n    \n    /**\n     Controls the time delay between the frames of an animated image, in milliseconds.\n     \n     - parameter delay:             The delay between the frames of an animated image, in milliseconds.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @objc(setDelayWithInt:)\n    @discardableResult\n    open func setDelay(_ delay: Int) -> Self {\n        return setDelay(String(delay))\n    }\n    \n    /**\n     Controls the time delay between the frames of an animated image, in milliseconds.\n     \n     - parameter delay:             The delay between the frames of an animated image, in milliseconds.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setDelay(_ delay: String) -> Self {\n        return setParam(TransformationParam.DELAY, value: delay)\n    }\n    \n    // MARK: - Set Values - RawTransformation\n    \n    /**\n     Add a raw transformation, it will be appended to the other transformation parameter.\n     the transformation must conform to [Cloudinary's transformation documentation](http://cloudinary.com/documentation/image_transformation_reference)\n     \n     - parameter rawTransformation:     The raw transformation to add.\n     \n     - returns:                         The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setRawTransformation(_ rawTransformation: String) -> Self {\n        return setParam(TransformationParam.RAW_TRANSFORMATION, value: rawTransformation)\n    }\n    \n    // MARK: - Set Values - Flags\n    \n    /**\n     Set one or more flags that alter the default transformation behavior.\n     \n     - parameter flags:     An array of the flags to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setFlagsWithArray:)\n    @discardableResult\n    open func setFlags(_ flags: [String]) -> Self {\n        return setFlags(flags.joined(separator: \".\"))\n    }\n    \n    /**\n     Set one or more flags that alter the default transformation behavior.\n     \n     - parameter flags:     An array of the flags to apply.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setFlags(_ flags: String) -> Self {\n        return setParam(TransformationParam.FLAGS, value: flags)\n    }\n    // MARK: - Set Values - DPR\n    /**\n     Deliver the image in the specified device pixel ratio.\n     \n     - parameter dpr:       The DPR ot set.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setDprWithFloat:)\n    @discardableResult\n    open func setDpr(_ dpr: Float) -> Self {\n        return setDpr(dpr.cldFloatFormat())\n    }\n    \n    /**\n     Deliver the image in the specified device pixel ratio. The parameter accepts any positive float value.\n     \n     - parameter dpr:       The DPR ot set.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setDpr(_ dpr: String) -> Self {\n        return setParam(TransformationParam.DPR, value: dpr)\n    }\n    // MARK: - Set Values - Zoom\n    /**\n     Control how much of the original image surrounding the face to keep when using either the 'crop' or 'thumb' cropping modes with face detection. default is 1.0.\n     \n     - parameter zoom:      The zoom ot set.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @objc(setZoomWithFloat:)\n    @discardableResult\n    open func setZoom(_ zoom: Float) -> Self {\n        return setZoom(zoom.cldFloatFormat())\n    }\n    \n    /**\n     Control how much of the original image surrounding the face to keep when using either the 'crop' or 'thumb' cropping modes with face detection. default is 1.0.\n     \n     - parameter zoom:      The zoom ot set.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setZoom(_ zoom: String) -> Self {\n        return setParam(TransformationParam.ZOOM, value: zoom)\n    }\n    \n    // MARK: - Set Values - AspectRatio\n    \n    /**\n     Resize or crop the image to a new aspect ratio using a nominator and dominator (e.g. 16 and 9 for 16:9).\n     This parameter is used together with a specified crop mode that determines how the image is adjusted to the new dimensions.\n     \n     - parameter nominator:     The nominator ot use.\n     - parameter denominator:   The dominator ot use.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setAspectRatio(nominator: Int, denominator: Int) -> Self {\n        return setAspectRatio(\"\\(nominator):\\(denominator)\")\n    }\n    \n    /**\n     Resize or crop the image to a new aspect ratio.\n     This parameter is used together with a specified crop mode that determines how the image is adjusted to the new dimensions.\n     \n     - parameter aspectRatio:   The aspect ratio ot use.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @objc(setAspectRatioWithFloat:)\n    @discardableResult\n    open func setAspectRatio(_ aspectRatio: Float) -> Self {\n        return setAspectRatio(aspectRatio.cldFloatFormat())\n    }\n    \n    /**\n     Resize or crop the image to a new aspect ratio.\n     This parameter is used together with a specified crop mode that determines how the image is adjusted to the new dimensions.\n     \n     - parameter aspectRatio:   The aspect ratio ot use.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setAspectRatio(_ aspectRatio: String) -> Self {\n        return setParam(TransformationParam.ASPECT_RATIO, value: aspectRatio)\n    }\n    \n    // MARK: - Set Values - CustomPreFunction\n    \n    /**\n     Set a custom pre-function, such as a call to a lambda function or a web-assembly function.\n     \n     - parameter customPreFunction: The custom pre-function to perform, see CLDCustomFunction.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setCustomPreFunction(_ customPreFunction: CLDCustomFunction) -> Self {\n        return setParam(TransformationParam.CUSTOM_FUNCTION, value: \"pre:\\(customPreFunction.description)\")\n    }\n    \n    // MARK: - Set Values - CustomFunction\n    \n    /**\n     Set a custom function, such as a call to a lambda function or a web-assembly function.\n     \n     - parameter customFunction:    The custom function to perform, see CLDCustomFunction.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setCustomFunction(_ customFunction: CLDCustomFunction) -> Self {\n        return setParam(TransformationParam.CUSTOM_FUNCTION, value: customFunction.description)\n    }\n    \n    // MARK: - Set Values - AudioCodec\n    \n    /**\n     Use the audio_codec parameter to set the audio codec or remove the audio channel completely as follows:\n     \n     * **none** removes the audio channel\n     * **aac** (mp4 or flv only)\n     * **vorbis** (ogv or webm only)\n     * **mp3** (mp4 or flv only)\n     \n     - parameter audioCodec:    The audio codec ot set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setAudioCodec(_ audioCodec: String) -> Self {\n        return setParam(TransformationParam.AUDIO_CODEC, value: audioCodec)\n    }\n    // MARK: - Set Values - AudioFrequency\n    /**\n     Use the audio_frequency parameter to control the audio sampling frequency.\n     This parameter represents an integer value in Hz.\n     See the documentation in the [Video transformations reference table](http://cloudinary.com/documentation/video_manipulation_and_delivery#video_transformations_reference) for the possible values.\n     \n     - parameter audioFrequency:    The audio frequency ot set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @objc(setAudioFrequencyWithInt:)\n    @discardableResult\n    open func setAudioFrequency(_ audioFrequency: Int) -> Self {\n        return setAudioFrequency(String(audioFrequency))\n    }\n    \n    /**\n     Use the audio_frequency parameter to control the audio sampling frequency.\n     This parameter represents an integer value in Hz.\n     See the documentation in the [Video transformations reference table](http://cloudinary.com/documentation/video_manipulation_and_delivery#video_transformations_reference) for the possible values.\n     \n     - parameter audioFrequency:    The audio frequency ot set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setAudioFrequency(_ audioFrequency: String) -> Self {\n        return setParam(TransformationParam.AUDIO_FREQUENCY, value: audioFrequency)\n    }\n    \n    // MARK: - Set Values - BitRate\n    /**\n     Use the bit_rate parameter for advanced control of the video bit rate.\n     This parameter controls the number of bits used to represent the video data.\n     The higher the bit rate, the higher the visual quality of the video, but the larger the file size as well.\n     \n     - parameter bitRate:    The bit rate ot set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @objc(setBitRateWithInt:)\n    @discardableResult\n    open func setBitRate(_ bitRate: Int) -> Self {\n        return setBitRate(String(bitRate))\n    }\n    \n    /**\n     Use the bit_rate parameter for advanced control of the video bit rate.\n     This parameter controls the number of bits used to represent the video data.\n     The higher the bit rate, the higher the visual quality of the video, but the larger the file size as well.\n     \n     - parameter bitRate:    The bit rate ot set in kilobytes.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setBitRate(kb bitRate: Int) -> Self {\n        return setBitRate(\"\\(bitRate)k\")\n    }\n    \n    /**\n     Use the bit_rate parameter for advanced control of the video bit rate.\n     This parameter controls the number of bits used to represent the video data.\n     The higher the bit rate, the higher the visual quality of the video, but the larger the file size as well.\n     Bit rate can take one of the following values:\n     \n     * An integer e.g. 120000.\n     * A string supporting ‘k’ and ‘m’ (kilobits and megabits respectively) e.g. 500k or 2m.\n     \n     - parameter bitRate:    The bit rate ot set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setBitRate(_ bitRate: String) -> Self {\n        return setParam(TransformationParam.BIT_RATE, value: bitRate)\n    }\n    \n    // MARK: - Set Values - VideoSampling\n    \n    /**\n     The total number of frames to sample from the original video. The frames are spread out over the length of the video, e.g. 20 takes one frame every 5%.\n     \n     - parameter frames:        The video sampling frames ot set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setVideoSampling(frames: Int) -> Self {\n        return setVideoSampling(String(frames))\n    }\n    \n    /**\n     Controls the time delay between the frames of an animated image, in milliseconds.\n     \n     - parameter delay:         The delay ot set in milliseconds.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setVideoSampling(delay: Float) -> Self {\n        return setVideoSampling(\"\\(delay.cldFloatFormat())s\")\n    }\n    \n    /**\n     Relevant for conversion of video to animated GIF or WebP.\n     If not specified, the resulting GIF or WebP samples the whole video (up to 400 frames, at up to 10 frames per second).\n     By default the duration of the animated image is the same as the duration of the video,\n     no matter how many frames are sampled from the original video (use the delay parameter to adjust the amount of time between frames).\n     \n     - parameter videoSampling:     The video sampling ot set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setVideoSampling(_ videoSampling: String) -> Self {\n        return setParam(TransformationParam.VIDEO_SAMPLING, value: videoSampling)\n    }\n    // MARK: - Set Values - Duration\n    /**\n     Offset in seconds or percent of a video, normally used together with the start_offset and end_offset parameters. Used to specify:\n     * The duration the video displays.\n     * The duration an overlay displays.\n     \n     - parameter seconds:       The duration to set in seconds.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setDuration(seconds: Float) -> Self {\n        return setDuration(seconds.cldFloatFormat())\n    }\n    \n    /**\n     Offset in seconds or percent of a video, normally used together with the start_offset and end_offset parameters. Used to specify:\n     * The duration the video displays.\n     * The duration an overlay displays.\n     \n     - parameter percent:       The duration percent to set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setDuration(percent: Int) -> Self {\n        return setDuration(\"\\(percent)p\")\n    }\n    \n    /**\n     Offset in seconds or percent of a video, normally used together with the start_offset and end_offset parameters. Used to specify:\n     * The duration the video displays.\n     * The duration an overlay displays.\n     \n     - parameter duration:      The duration to set in seconds.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setDuration(_ duration: String) -> Self {\n        return setParam(TransformationParam.DURATION, value: duration)\n    }\n    // MARK: - Set Values - StartOffset\n    /**\n     Set an offset in seconds to cut a video at the start.\n     \n     - parameter seconds:       The start time to set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setStartOffset(seconds: Float) -> Self {\n        return setStartOffset(seconds.cldFloatFormat())\n    }\n    \n    /**\n     Set an offset in percent to cut a video at the start.\n     \n     - parameter percent:       The percent of time to cut.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setStartOffset(percent: Int) -> Self {\n        return setStartOffset(\"\\(percent)p\")\n    }\n    \n    /**\n     Set an offset in seconds or percent of a video to cut a video at the start.\n     \n     - parameter duration:      The start time to set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    \n    @discardableResult\n    open func setStartOffset(_ duration: String) -> Self {\n        return setParam(TransformationParam.START_OFFSET, value: duration)\n    }\n    // MARK: - Set Values - EndOffset\n    /**\n     Set an offset in seconds to cut a video at the end.\n     \n     - parameter seconds:       The end time to set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setEndOffset(seconds: Float) -> Self {\n        return setEndOffset(seconds.cldFloatFormat())\n    }\n    \n    /**\n     Set an offset in percent to cut a video at the end.\n     \n     - parameter percent:       The percent of time to cut.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setEndOffset(percent: Int) -> Self {\n        return setEndOffset(\"\\(percent)p\")\n    }\n    \n    /**\n     Set an offset in seconds or percent of a video to cut a video at the end.\n     \n     - parameter duration:      The end time to set.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setEndOffset(_ duration: String) -> Self {\n        return setParam(TransformationParam.END_OFFSET, value: duration)\n    }\n    // MARK: - Set Values - VideoCodecAndProfileAndLevel\n    /**\n     Used to determine the video codec, video profile and level to use.\n     You can set this parameter to auto instead.\n\n     - parameter videoCodec:        The video codec to set.\n     - parameter videoProfile:      The video profile to set.\n     - parameter level:             The level to set.\n\n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setVideoCodecAndProfileAndLevel(_ videoCodec: String, videoProfile: String, level: String? = nil) -> Self {\n        return level == nil ? setVideoCodec(\"\\(videoCodec):\\(videoProfile)\") : setVideoCodec(\"\\(videoCodec):\\(videoProfile):\\(level!)\")\n    }\n    // MARK: - Set Values - VideoCodecAndProfileAndLevelAndBframes\n    /**\n     Used to determine the video codec, video profile and level to use.\n     You can set this parameter to auto instead.\n\n     - parameter videoCodec:        The video codec to set.\n     - parameter videoProfile:      The video profile to set.\n     - parameter level:             The level to set.\n     - parameter bframes:           Should use B-frames.\n\n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setVideoCodecAndProfileAndLevelAndBFrames(_ videoCodec: String, videoProfile: String, level: String? = nil, bframes: Bool? = nil) -> Self {\n        var videoCodec = \"\\(videoCodec):\\(videoProfile)\"\n        if let level = level {\n            videoCodec.append(\":\\(level)\" + (bframes == false ? \":bframes_no\" : \"\"))\n        }\n        return setVideoCodec(videoCodec)\n    }\n    // MARK: - Set Values - VideoCodec\n    /**\n     Used to determine the video codec to use.\n     You can set this parameter to auto instead.\n     \n     - parameter videoCodec:        The video codec to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setVideoCodec(_ videoCodec: String) -> Self {\n        return setParam(TransformationParam.VIDEO_CODEC, value: videoCodec)\n    }\n    \n    // MARK: Setters\n    \n    fileprivate func setParam(_ key: TransformationParam, value: String) -> Self {\n        return setParam(key.rawValue, value: value)\n    }\n    \n    fileprivate func setParam(_ key: TransformationParam, expression: CLDExpression, fallback: String) -> Self {\n        \n        if expression.currentValue.isEmpty {\n            return setParam(key, value: fallback)\n        } else {\n            return setParam(key, value: expression.asString())\n        }\n    }\n    \n    @discardableResult\n    open func setParam(_ key: String, value: String) -> Self {\n        currentTransformationParams[key] = value\n        return self\n    }\n    \n    // MARK: - Convenience\n    \n    /**\n     A convenience method to set video cutting in seconds. Must provide an array with exactly 2 values: 1. start offset. 2. end offset.\n     \n     - parameter seconds:           The array of both start and end offsets to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    func setOffset(seconds: [Float]) -> Self {\n        guard let\n            start = seconds.first,\n            let end = seconds.last else {\n                return self\n        }\n        return setOffset([start.cldFloatFormat(), end.cldFloatFormat()])\n    }\n    \n    /**\n     A convenience method to set video cutting in percent. Must provide an array with exactly 2 values: 1. start offset. 2. end offset.\n     \n     - parameter seconds:           The array of both start and end offsets to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    func setOffset(percents: [Int]) -> Self {\n        guard let\n            start = percents.first,\n            let end = percents.last else {\n                return self\n        }\n        return setOffset([\"\\(start)p\", \"\\(end)p\"])\n    }\n    \n    /**\n     A convenience method to set video cutting in seconds or percent. \n     Should provide an array with 2 values: 1. start offset. 2. end offset. Or one value for both.\n     \n     - parameter seconds:           The array of both start and end offsets to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    func setOffset(_ durations: [String]) -> Self {\n        guard let\n            start = durations.first,\n            let end = durations.last else {\n                return self\n        }\n        setStartOffset(start)\n        setEndOffset(end)\n        return self\n    }\n    \n    /**\n     Shortcut to set video cutting in seconds using a combination of start_offset and end_offset values.\n     \n     - parameter startSeconds:           The start time to set.\n     - parameter endSeconds:             The end time to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setStartOffsetAndEndOffset(startSeconds: Float, endSeconds: Float) -> Self {\n        return setStartOffset(seconds: startSeconds).setEndOffset(seconds: endSeconds)\n    }\n    \n    /**\n     Shortcut to set video cutting in percent of video using a combination of start_offset and end_offset values.\n     \n     - parameter startPercent:           The start time to set.\n     - parameter endPercent:             The end time to set.\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setStartOffsetAndEndOffset(startPercent: Int, endPercent: Int) -> Self {\n        return setStartOffset(percent: startPercent).setEndOffset(percent: endPercent)\n    }\n    \n    /**\n     Set the frames-per-second of the video.\n     \n     - parameter fps: A CLDFps configured with the required parameters (see CLDFps for details).\n     \n     - returns:                     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setFps(_ fps: CLDFps) -> Self {\n        return setParam(TransformationParam.FPS, value: fps.description)\n    }\n    \n    /**\n     Set the frames-per-second of the video.\n     \n     - parameter fps: Frames per second as string.\n     \n     - returns:     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    @objc(setFpsWithString:)\n    open func setFps(_ fps: String) -> Self {\n        return setFps(CLDFps.fromString(fps))\n    }\n    \n    /**\n     Set the frames-per-second of the video.\n     \n     - parameter fps: Frames per seconds as float.\n     \n     - returns:     The same instance of CLDTransformation.\n     */\n    @discardableResult\n    @objc(setFpsWithFloat:)\n    open func setFps(_ fps: Float) -> Self {\n        return setFps(CLDFps.fromFloat(fps))\n    }\n    \n    /**\n     Set an overlay using the helper class CLDLayer.\n     \n     - parameter layer:     The layer to add as an overlay.\n     \n     - returns:                 The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setOverlayWithLayer(_ layer: CLDLayer) -> Self {\n        if let layerString = layer.asString() {\n            return setOverlay(layerString)\n        }\n        else {\n            return setOverlay(\"\")\n        }\n    }\n    \n    /**\n     Set an underlay using the helper class CLDLayer.\n     \n     - parameter layer:     The layer to add as an underlay.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setUnderlayWithLayer(_ layer: CLDLayer) -> Self {\n        if let layerString = layer.asString() {\n            return setUnderlay(layerString)\n        }\n        else {\n            return setUnderlay(\"\")\n        }\n    }\n    \n    /**\n     A convenience method to set the transformation X and Y parameters.\n     \n     - parameter point:     The top left pont to set.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setTopLeftPoint(_ point: CGPoint) -> Self {\n        return setX(Float(point.x)).setY(Float(point.y))\n    }\n    \n    @discardableResult\n    open func setKeyframeInterval(interval: Float) -> Self {\n        return setKeyframeInterval(interval.description)\n    }\n    \n    @discardableResult\n    open func setKeyframeInterval(_ interval: String) -> Self {\n        return setParam(TransformationParam.KEYFRAME_INTERVAL, value: interval)\n    }\n    \n    @discardableResult\n    open func setStreamingProfile(_ streamingProfile: String) -> Self {\n        return setParam(TransformationParam.STREAMING_PROFILE, value: streamingProfile)\n    }\n    \n    // MARK: - Actions\n    \n    /**\n     Cloudinary supports powerful image transformations that are applied on the fly using dynamic URLs,\n     and you can also combine multiple transformations together as part of a single delivery request, e.g. crop an image and then add a border.\n     In certain cases you may want to perform additional transformations on the result of a single transformation request.\n     In order to do that, you can chain the transformations together.\n     \n     In practice, the chain allows you to start seting properties to a new transformation,\n     which will be chained to the transformation you worked on, even though you still use the same CLDTransformation instance.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func chain() -> Self {\n        \n        guard !currentTransformationParams.isEmpty else { return self }\n        \n        transformations.append(currentTransformationParams)\n        currentTransformationParams = [:]\n        return self\n    }\n    \n    public func asString() -> String? {\n        chain()\n        var components: [String] = []\n        for params in self.transformations {\n            if let singleTransStringRepresentation = self.getStringRepresentationFromParams(params) {\n                components.append(singleTransStringRepresentation)\n            }\n            else {\n                return nil\n            }\n        }\n        return components.joined(separator: \"/\")\n    }\n    \n    // MARK: - Private\n    \n    internal func getStringRepresentationFromParams(_ params: [String : String]) -> String? {\n        \n        let emptyParams = params.filter { $0.0.isEmpty || $0.1.isEmpty }\n        if !emptyParams.isEmpty {\n            printLog(.error, text: \"An empty string key or value are not allowed.\")\n            return nil\n        }\n        \n        let components: [String] = params.sorted { $0.0 < $1.0 }\n            .filter { $0.0 != TransformationParam.RAW_TRANSFORMATION.rawValue &&\n                $0.0 != TransformationParam.VARIABLES.rawValue &&\n                $0.0 != TransformationParam.IF_PARAM.rawValue &&\n                !$0.1.isEmpty }\n            .compactMap {\n                return \"\\($0)_\\($1)\"\n            }\n        \n        var finalComponents: [String] = [String]()\n        \n        if let ifConditions = params[TransformationParam.IF_PARAM.rawValue], !ifConditions.isEmpty {\n            finalComponents.append(TransformationParam.IF_PARAM.rawValue + CLDTransformation.elementsSeparator + ifConditions)\n        }\n        \n        if let complexVariables = params[TransformationParam.VARIABLES.rawValue], !complexVariables.isEmpty {\n            finalComponents.append(complexVariables)\n        }\n        \n        finalComponents.append(contentsOf: components)\n        \n        if let rawTrans = params[TransformationParam.RAW_TRANSFORMATION.rawValue], !rawTrans.isEmpty {\n            finalComponents.append(rawTrans)\n        }\n        \n        return finalComponents.joined(separator: CLDTransformation.transformationContentSeparator)\n    }\n    \n    // MARK: - Params\n    \n    internal enum TransformationParam: String {\n        case WIDTH =                        \"w\"\n        case HEIGHT =                       \"h\"\n        case NAMED =                        \"t\"\n        case CROP =                         \"c\"\n        case BACKGROUND =                   \"b\"\n        case COLOR =                        \"co\"\n        case EFFECT =                       \"e\"\n        case ANGLE =                        \"a\"\n        case OPACITY =                      \"o\"\n        case BORDER =                       \"bo\"\n        case X =                            \"x\"\n        case Y =                            \"y\"\n        case RADIUS =                       \"r\"\n        case QUALITY =                      \"q\"\n        case DEFAULT_IMAGE =                \"d\"\n        case GRAVITY =                      \"g\"\n        case COLOR_SPACE =                  \"cs\"\n        case PREFIX =                       \"p\"\n        case OVERLAY =                      \"l\"\n        case UNDERLAY =                     \"u\"\n        case FETCH_FORMAT =                 \"f\"\n        case DENSITY =                      \"dn\"\n        case PAGE =                         \"pg\"\n        case DELAY =                        \"dl\"\n        case FLAGS =                        \"fl\"\n        case DPR =                          \"dpr\"\n        case ZOOM =                         \"z\"\n        case ASPECT_RATIO =                 \"ar\"\n        case CUSTOM_FUNCTION =              \"fn\"\n        case AUDIO_CODEC =                  \"ac\"\n        case AUDIO_FREQUENCY =              \"af\"\n        case BIT_RATE =                     \"br\"\n        case VIDEO_SAMPLING =               \"vs\"\n        case DURATION =                     \"du\"\n        case START_OFFSET =                 \"so\"\n        case END_OFFSET =                   \"eo\"\n        case VIDEO_CODEC =                  \"vc\"\n        case RAW_TRANSFORMATION =           \"raw_transformation\"\n        case VARIABLES =                    \"variables\"\n        case IF_PARAM =                     \"if\"\n        case KEYFRAME_INTERVAL =            \"ki\"\n        case FPS =                          \"fps\"\n        case STREAMING_PROFILE =            \"sp\"\n    }\n    \n    \n    // MARK: CLDBaseParam\n    @objc public class CLDBaseParam: NSObject {\n        fileprivate let param: String\n        \n        fileprivate init(_ components: [String]) {\n            self.param = components.joined(separator: \":\")\n        }\n        \n        fileprivate convenience init(_ components: String...) {\n            self.init(components)\n        }\n        \n        override public var description: String {\n            get {\n                return param\n            }\n        }\n    }\n    \n    // MARK: CLDQuality\n    \n    /**\n     Image quality configuration object\n     */\n    @objc public class CLDQuality: CLDBaseParam {\n        \n        /**\n         Build an instance of CLDQuality configured for fixed quality.\n         \n         - parameter level: Quality level to set. Valid range is 1 through 100.\n         */\n        public static func fixed(_ level: Int) -> CLDQuality {\n            return CLDQuality(level.description)\n        }\n        \n        /**\n         Build an instance of CLDQuality configured for automatic quality. See CLDAutoQuality enum for details.\n         \n         - parameter level: Auto quality level.\n         */\n        public static func auto(_ level: CLDQualityAuto? = nil) -> CLDQuality {\n            if let level = level {\n                return CLDQuality(\"auto\", level.description)\n            } else {\n                return CLDQuality(\"auto\")\n            }\n        }\n        \n        /**\n         Build an instance of CLDQuality configured to use jpegmini addon for automatic quality.\n         */\n        public static func jpegMini() -> CLDQuality {\n            return CLDQuality(\"jpegmini\")\n        }\n    }\n    \n    /**\n     Automatic optimal quality settings: the smallest file size without affecting their perceptual quality.\n     * best: Automatically calculate the optimal quality for images using a less aggressive algorithm\n     * good: Automatically calculate the optimal quality for an image\n     * eco: Automatically calculate the optimal quality for images using a more aggressive algorithm\n     * low: Automatically calculate the optimal quality for images using the most aggressive algorithm\n     */\n    @objc public enum CLDQualityAuto: Int, CustomStringConvertible {\n        case best, good, eco, low\n        \n        public var description: String {\n            get {\n                switch self {\n                case .best:         return \"best\"\n                case .good:         return \"good\"\n                case .eco:          return \"eco\"\n                case .low:          return \"low\"\n                }\n            }\n        }\n    }\n    \n    // MARK: CLDCustomFunction\n    \n    /**\n     Custom function configuration object\n     */\n    @objc public class CLDCustomFunction: CLDBaseParam {\n        \n        /**\n         Build an instance of CLDCustomFunction configured for web-assembly custom function.\n         \n         - parameter publicId: Public id of the web assembly file.\n         */\n        @objc public static func wasm(_ publicId: String) -> CLDCustomFunction {\n            return CLDCustomFunction(\"wasm\", publicId)\n        }\n        \n        /**\n         Build an instance of CLDCustomFunction configured for remote lambda custom function.\n         \n         - parameter url: public url of the aws lambda function\n         */\n        @objc public static func remote(_ url: String) -> CLDCustomFunction {\n            return CLDCustomFunction(\"remote\", url.cldBase64UrlEncode())\n        }\n    }\n    \n    // MARK: FPS\n    /**\n     FPS parameters configuration object. For simple cases you can pass a float/string\n     directly to CLDTransformation.setFps(). This class is used for more complex values (e.g. ranges).\n     */\n    @objc public class CLDFps: CLDBaseParam {\n        /**\n         Build an instance of CLDFps based on a string.\n         \n         - parameter fps: The fps value as string\n         */\n        public static func fromString(_ fps: String) -> CLDFps {\n            return CLDFps(fps);\n        }\n        \n        /**\n         Build an instance of CLDFps based on a float.\n         \n         - parameter fps: The fps value as float\n         */\n        public static func fromFloat(_ fps: Float) -> CLDFps {\n            return CLDFps(fps.cldCleanFormat());\n        }\n        \n        /**\n         Build an instance of CLDFps based on a range of string values. Note: At least one parameter must not be nil.\n         \n         - parameter start: The fps start value as string\n         - parameter start: The fps end value as string\n         */\n        public static func range(start: String? = nil, end: String? = nil) -> CLDFps {\n            return CLDFps(\"\\(start ?? \"\")-\\(end ?? \"\")\");\n        }\n        \n        /**\n         Build an instance of CLDFps based on a range of float values. Note: At least one parameter must not be nil.\n         \n         - parameter start: The fps start value as float\n         - parameter start: The fps end value as float\n         */\n        public static func range(start: Float? = nil, end: Float? = nil) -> CLDFps {\n            return CLDFps(\"\\(start?.cldCleanFormat() ?? \"\")-\\(end?.cldCleanFormat() ?? \"\")\");\n        }\n    }\n    \n    // MARK: Crop\n    \n    @objc public enum CLDCrop: Int, CustomStringConvertible {\n        case fill, crop, scale, fit, limit, mFit, lFill, pad, lPad, mPad, thumb, imaggaCrop, imaggaScale\n        \n        public var description: String {\n            get {\n                switch self {\n                case .fill:         return \"fill\"\n                case .crop:         return \"crop\"\n                case .scale:        return \"scale\"\n                case .fit:          return \"fit\"\n                case .limit:        return \"limit\"\n                case .mFit:         return \"mfit\"\n                case .lFill:        return \"lfill\"\n                case .pad:          return \"pad\"\n                case .lPad:         return \"lpad\"\n                case .mPad:         return \"mpad\"\n                case .thumb:        return \"thumb\"\n                case .imaggaCrop:   return \"imagga_crop\"\n                case .imaggaScale:  return \"imagga_scale\"\n                }\n            }\n        }\n    }\n    \n    // MARK: Effect\n    \n    @objc public enum CLDEffect: Int, CustomStringConvertible {\n        case hue, red, green, blue, negate, brightness, sepia, grayscale, blackwhite, saturation, colorize, contrast, autoContrast, vibrance, autoColor, improve, autoBrightness, fillLight, viesusCorrect, gamma, screen, multiply, overlay, makeTransparent, trim, shadow, distort, shear, displace, oilPaint, redeye, advRedeye, vignette, gradientFade, pixelate, pixelateRegion, pixelateFaces, blur, blurRegion, blurFaces, sharpen, unsharpMask, orderedDither, art, assistColorblind, preview\n        \n        public var description: String {\n            get {\n                switch self {\n                case .hue:              return \"hue\"\n                case .red:              return \"red\"\n                case .green:            return \"green\"\n                case .blue:             return \"blue\"\n                case .negate:           return \"negate\"\n                case .brightness:       return \"brightness\"\n                case .sepia:            return \"sepia\"\n                case .grayscale:        return \"grayscale\"\n                case .blackwhite:       return \"blackwhite\"\n                case .saturation:       return \"saturation\"\n                case .colorize:         return \"colorize\"\n                case .contrast:         return \"contrast\"\n                case .autoContrast:     return \"auto_contrast\"\n                case .vibrance:         return \"vibrance\"\n                case .autoColor:        return \"auto_color\"\n                case .improve:          return \"improve\"\n                case .autoBrightness:   return \"auto_brightness\"\n                case .fillLight:        return \"fill_light\"\n                case .viesusCorrect:    return \"viesus_correct\"\n                case .gamma:            return \"gamma\"\n                case .screen:           return \"screen\"\n                case .multiply:         return \"multiply\"\n                case .overlay:          return \"overlay\"\n                case .makeTransparent:  return \"make_transparent\"\n                case .trim:             return \"trim\"\n                case .shadow:           return \"shadow\"\n                case .distort:          return \"distort\"\n                case .shear:            return \"shear\"\n                case .displace:         return \"displace\"\n                case .oilPaint:         return \"oil_paint\"\n                case .redeye:           return \"redeye\"\n                case .advRedeye:        return \"adv_redeye\"\n                case .vignette:         return \"vignette\"\n                case .gradientFade:     return \"gradient_fade\"\n                case .pixelate:         return \"pixelate\"\n                case .pixelateRegion:   return \"pixelate_region\"\n                case .pixelateFaces:    return \"pixelate_faces\"\n                case .blur:             return \"blur\"\n                case .blurRegion:       return \"blur_region\"\n                case .blurFaces:        return \"blur_faces\"\n                case .sharpen:          return \"sharpen\"\n                case .unsharpMask:      return \"unsharp_mask\"\n                case .orderedDither:    return \"ordered_dither\"\n                case .art:              return \"art\"\n                case .assistColorblind: return \"assist_colorblind\"\n                case .preview:          return \"preview\"\n                }\n            }\n        }\n    }\n    \n    // MARK: Artistic Effects\n    @objc public enum CLDArtFilters: Int, CustomStringConvertible {\n        case alDente, athena, audrey, aurora, daguerre, eucalyptus, fes, frost, hairspray, hokusai, incognito, linen, peacock, primavera, quartz, redRock, refresh, sizzle, sonnet, ukulele, zorro\n        \n        public var description: String {\n            get {\n                switch self {\n                case .alDente:           return \"al_dente\"\n                case .athena:            return \"athena\"\n                case .audrey:            return \"audrey\"\n                case .aurora:            return \"aurora\"\n                case .daguerre:          return \"daguerre\"\n                case .eucalyptus:        return \"eucalyptus\"\n                case .fes:               return \"fes\"\n                case .frost:             return \"frost\"\n                case .hairspray:         return \"hairspray\"\n                case .hokusai:           return \"hokusai\"\n                case .incognito:         return \"incognito\"\n                case .linen:             return \"linen\"\n                case .peacock:           return \"peacock\"\n                case .primavera:         return \"primavera\"\n                case .quartz:            return \"quartz\"\n                case .redRock:           return \"red_rock\"\n                case .refresh:           return \"refresh\"\n                case .sizzle:            return \"sizzle\"\n                case .sonnet:            return \"sonnet\"\n                case .ukulele:           return \"ukulele\"\n                case .zorro:             return \"zorro\"\n                }\n            }\n        }\n    }\n    \n    // MARK: Gravity\n    \n    @objc public enum CLDGravity: Int, CustomStringConvertible {\n        case center, auto, face, faceCenter, faces, facesCenter, advFace, advFaces, advEyes, north, northWest, northEast, south, southWest, southEast, east, west, xyCenter, custom, customFace, customFaces, customAdvFace, customAdvFaces, autoOcrText, ocrText, ocrTextAdvOcr\n        \n        public var description: String {\n            get {\n                switch self {\n                case .center:           return \"center\"\n                case .auto:             return \"auto\"\n                case .face:             return \"face\"\n                case .faceCenter:       return \"face:center\"\n                case .faces:            return \"faces\"\n                case .facesCenter:      return \"faces:center\"\n                case .advFace:          return \"adv_face\"\n                case .advFaces:         return \"adv_faces\"\n                case .advEyes:          return \"adv_eyes\"\n                case .north:            return \"north\"\n                case .northWest:        return \"north_west\"\n                case .northEast:        return \"north_east\"\n                case .south:            return \"south\"\n                case .southWest:        return \"south_west\"\n                case .southEast:        return \"south_east\"\n                case .west:             return \"west\"\n                case .east:             return \"east\"\n                case .xyCenter:         return \"xy_center\"\n                case .custom:           return \"custom\"\n                case .customFace:       return \"custom:face\"\n                case .customFaces:      return \"custom:faces\"\n                case .customAdvFace:    return \"custom:adv_face\"\n                case .customAdvFaces:   return \"custom:adv_faces\"\n                case .autoOcrText:      return \"auto:ocr_text\"\n                case .ocrText:          return \"ocr_text\"\n                case .ocrTextAdvOcr:    return \"ocr_text:adv_ocr\"\n                }\n            }\n        }\n    }\n    \n}\n\n// MARK: - Expressions\nextension CLDTransformation\n{\n    @objc(setWidthWithExpression:)\n    @discardableResult\n    public func setWidth(_ input: CLDExpression) -> Self {\n        \n        return setParam(TransformationParam.WIDTH, value: input.asString())\n    }\n    \n    @objc(setHeightWithExpression:)\n    @discardableResult\n    public func setHeight(_ input: CLDExpression) -> Self {\n        \n        return setParam(TransformationParam.HEIGHT, value: input.asString())\n    }\n    \n    @objc(setXFromExpression:)\n    @discardableResult\n    public func setX(_ input: CLDExpression) -> Self {\n        \n        return setParam(TransformationParam.X, value: input.asString())\n    }\n    \n    @objc(setYFromExpression:)\n    @discardableResult\n    public func setY(_ input: CLDExpression) -> Self {\n        \n        return setParam(TransformationParam.Y, value: input.asString())\n    }\n    \n    @objc(setRadiusFromExpression:)\n    @discardableResult\n    public func setRadius(_ input: CLDExpression) -> Self {\n        \n        return setParam(TransformationParam.RADIUS, value: input.asString())\n    }\n    \n    @objc(setStartOffsetFromExpression:)\n    @discardableResult\n    public func setStartOffset(_ input: CLDExpression) -> Self {\n        \n        return setParam(TransformationParam.START_OFFSET, value: input.asString())\n    }\n    \n    @objc(setEndOffsetFromExpression:)\n    @discardableResult\n    public func setEndOffset(_ input: CLDExpression) -> Self {\n        \n        return setParam(TransformationParam.END_OFFSET, value: input.asString())\n    }\n}\n// MARK: - Condition Expression\nextension CLDTransformation\n{\n    // MARK: - ifCondition with content\n    @objc(ifConditionFromString:)\n    @discardableResult\n    public func ifCondition(_ condition: String) -> Self {\n        \n        let conditionObject = CLDConditionExpression(value: condition)\n        \n        guard !conditionObject.currentValue.isEmpty else {\n            \n            return setParam(TransformationParam.IF_PARAM, value: condition)\n        }\n        \n        return ifCondition(conditionObject)\n    }\n    \n    @discardableResult\n    public func ifCondition(_ condition: CLDConditionExpression) -> Self {\n        return setParam(TransformationParam.IF_PARAM, value: condition.asString())\n    }\n    \n    @discardableResult\n    public func ifCondition(_ condition: CLDConditionExpression, then transformation: CLDExpression) -> Self {\n        return ifCondition(condition).setParam(transformation.currentKey, value: transformation.currentValue)\n    }\n    \n    // MARK: - ifCondition state\n    @objc(ifCondition)\n    @discardableResult\n    public func ifCondition() -> CLDConditionExpression {\n        \n        let condition = CLDConditionExpression()\n        condition.relatedTransformation = self\n        currentCondition =  condition\n        return  condition\n    }\n    \n    // MARK: - ifElse\n    @objc(ifElse)\n    @discardableResult\n    public func ifElse() -> Self {\n        \n        chain()\n        return setParam(TransformationParam.IF_PARAM, value: \"else\")\n    }\n    \n    // MARK: - endIf\n    @objc(endIf)\n    @discardableResult\n    public func endIf() -> Self {\n        \n        chain()\n        \n        guard !transformations.isEmpty else { return self }\n        \n        let transformSize = transformations.count\n        let loopSize = transformSize - 1\n        \n        for index in (0...loopSize).reversed() {\n            \n            var segment = transformations[index]; // [..., {if: \"w_gt_1000\",c: \"fill\", w: 500}, ...]\n            \n            if  let value = segment[TransformationParam.IF_PARAM.rawValue] { // if: \"w_gt_1000\"\n                \n                if value == \"end\" {\n                    break\n                }\n                \n                if segment.keys.count > 1 {\n                    segment.removeValue(forKey: TransformationParam.IF_PARAM.rawValue) // {c: fill, w: 500}\n                    transformations[index] = segment  // [..., {c: fill, w: 500}, ...]\n                    transformations.insert([TransformationParam.IF_PARAM.rawValue:value], at: index) // [..., \"if_w_gt_1000\", {c: fill, w: 500}, ...]\n                }\n                \n                // otherwise keep looking for if_condition\n                if value != \"else\" {\n                    break\n                }\n            }\n        }\n        setParam(TransformationParam.IF_PARAM.rawValue, value: \"end\")\n        return chain()\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/CLDVariable.swift",
    "content": "//\n//  CLDVariable.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal func CLDThrowFatalError(with message: String) {\n    // fatalError(message)\n}\n\n@objcMembers open class CLDVariable: NSObject {\n    \n    public var value: String\n    public var name : String {\n        didSet { self.addNamePrefixIfNeeded() }\n    }\n    \n    internal var isValid : Bool {\n        return checkValidName(name) && !value.isEmpty\n    }\n    \n    static public  let variableNamePrefix : String = \"$\"\n    \n    static private let collectionPrefix   : String = \"!\"\n    static private let collectionSuffix   : String = \"!\"\n    static private let collectionSeparator: String = \":\"\n    \n    static internal let elementsSeparator: String = \"_\"\n    \n    static private let separator: String = \",\"\n    \n    static private let nameRegex: String = \"^\\\\$[a-zA-Z][a-zA-Z0-9]*$\"\n\n    // MARK: - Init\n    public override init() {\n        self.name  = String()\n        self.value = String()\n        super.init()\n        self.addNamePrefixIfNeeded()\n    }\n    \n    @objc(initWithName:stringValue:)\n    public init(name variableName: String, value variableValue: String) {\n        \n        self.name  = variableName\n        \n        if variableValue.hasPrefix(CLDVariable.variableNamePrefix) {\n            self.value = CLDExpression(value: variableValue).asString()\n        } else {\n            self.value = variableValue\n        }\n        super.init()\n        self.addNamePrefixIfNeeded()\n    }\n    \n    @objc(initWithName:doubleValue:)\n    public init(name variableName: String, value variableValue: Double) {\n        self.name = variableName\n        self.value = String(variableValue)\n        super.init()\n        self.addNamePrefixIfNeeded()\n    }\n    \n    @objc(initWithName:intValue:)\n    public init(name variableName: String, value variableValue: Int) {\n        self.name = variableName\n        self.value = String(variableValue)\n        super.init()\n        self.addNamePrefixIfNeeded()\n    }\n    \n    public init(name variableName: String, values: [String]) {\n        \n        self.name = variableName\n        \n        if values.isEmpty {\n            self.value = String()\n        } else {\n            self.value = CLDVariable.collectionPrefix + values.joined(separator: CLDVariable.collectionSeparator) + CLDVariable.collectionSuffix\n        }\n        \n        super.init()\n        self.addNamePrefixIfNeeded()\n    }\n    \n    // MARK: - Public methods\n    public func asString() -> String {\n        guard checkValidName(name) else { return String() }\n        return name + CLDVariable.elementsSeparator + value\n    }\n    \n    public func asParams() -> [String : String] {\n        guard checkValidName(name) else { return [String:String]() }\n        return [name:value]\n    }\n    \n    // MARK: - Private methods\n    private func checkValidName(_ name: String) -> Bool {\n        let regex = try! NSRegularExpression(pattern: CLDVariable.nameRegex, options: .caseInsensitive)\n        let range = NSRange(location: 0, length: name.count)\n        \n        let isValid = regex.firstMatch(in: name, options: [], range: range) != nil\n        \n        if !isValid {\n            CLDThrowFatalError(with: \"\\(#function) failed!\")\n        }\n        return isValid\n    }\n    \n    private func addNamePrefixIfNeeded() {\n        guard !checkValidName(name) else { return }\n        guard !name.hasPrefix(CLDVariable.variableNamePrefix) else { return }\n        name = addPrefix(to: name)\n    }\n    \n    private func addPrefix(to name: String) -> String {\n        return CLDVariable.variableNamePrefix + name\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Layers/CLDFetchLayer.swift",
    "content": "//\n//  CLDFetchLayer.swift\n//  Cloudinary\n//\n//  Created by Nitzan Jaitman on 19/02/2019.\n//  Copyright © 2019 Cloudinary. All rights reserved.\n//\n\nimport Foundation\n\n@objcMembers open class CLDFetchLayer: CLDLayer {\n   \n    // MARK: - Init\n    \n    /**\n     Initialize a CLDFetchLayer instance.\n     \n     - parameter url: The url of the remote resource to fetch\n     \n     - returns: The new CLDFetchLayer instance.\n     */\n    public init(url: String) {\n        super.init()\n        setPublicId(publicId: url.cldBase64UrlEncode())\n        resourceType = String(describing: LayerResourceType.fetch)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Layers/CLDLayer.swift",
    "content": "//\n//  CLDLayer.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The CLDLayer is used to help adding an overlay or underlay layer to a transformation.\n*/\n@objcMembers open class CLDLayer: NSObject {\n    \n    internal var publicId: String?\n    internal var format: String?\n    internal var resourceType: String?\n    internal var type: String?    \n    \n    // MARK: - Init\n    \n    /**\n    Initialize a CLDLayer instance.\n    \n    -returns: The new CLDLayer instance.\n    */\n    @discardableResult\n    public override init() {\n        super.init()\n    }\n    \n    // MARK: - Set Values\n    \n    /**\n    The identifier of the image to use as a layer.\n    \n    - parameter publicId:      The identifier of the image to use as a layer.\n    \n    - returns:                 The same instance of CLDLayer.\n    */\n    @discardableResult\n    open func setPublicId(publicId: String) -> CLDLayer {\n        self.publicId = publicId\n        return self\n    }\n    \n    /**\n     The format of the image to use as a layer.\n     \n     - parameter format:        The format of the image to use as a layer.\n     \n     - returns:                 The same instance of CLDLayer.\n     */\n    @discardableResult\n    open func setFormat(format: String) -> CLDLayer {\n        self.format = format\n        return self\n    }\n    \n    /**\n     Set the layer resource type.\n     \n     - parameter resourceType:      The layer resource type.\n     \n     - returns:                     The same instance of CLDLayer.\n     */\n    @objc(setResourceTypeFromLayerResourceType:)\n    @discardableResult\n    open func setResourceType(_ resourceType: LayerResourceType) -> CLDLayer {\n        return setResourceType(String(describing: resourceType))\n    }\n    \n    /**\n     Set the layer resource type.\n     \n     - parameter resourceType:      The layer resource type.\n     \n     - returns:                     The same instance of CLDLayer.\n     */\n    @objc(setResourceTypeFromString:)\n    @discardableResult\n    open func setResourceType(_ resourceType: String) -> CLDLayer {\n        self.resourceType = resourceType\n        return self\n    }\n    \n    /**\n     Set the layer type.\n     \n     - parameter type:  The layer type.\n     \n     - returns:         The same instance of CLDLayer.\n     */\n    @objc(setTypeFromType:)\n    @discardableResult\n    open func setType(_ type: CLDType) -> CLDLayer {\n        return setType(String(describing: type))\n    }\n    \n    /**\n     Set the layer type.\n     \n     - parameter rawType:  The layer type.\n     \n     - returns:         The same instance of CLDLayer.\n     */\n    @objc(setTypeFromString:)\n    @discardableResult\n    open func setType(_ rawType: String) -> CLDLayer {\n        type = rawType\n        return self\n    }\n    \n    // MARK: - Helpers\n    \n    fileprivate func isResourceTypeTextual(_ resourceType: String?) -> Bool {\n        guard let resourceType = resourceType else {\n                return false\n        }\n        return resourceType == String(describing: LayerResourceType.text) || resourceType == String(describing: LayerResourceType.subtitles)\n    }\n    \n    internal func getFinalPublicId() -> String? {\n        var finalPublicId: String?\n        if let pubId = publicId , !pubId.isEmpty, let format = format , !format.isEmpty {\n            finalPublicId = \"\\(pubId).\\(format)\"\n        }\n        return finalPublicId ?? publicId\n    }\n    \n    internal func getStringComponents() -> [String]? {\n        var components: [String] = []\n        \n        if publicId == nil, let resourceType = resourceType , resourceType != String(describing: LayerResourceType.text) {\n            printLog(.error, text: \"Must supply publicId for non-text layer\")\n            return nil\n        }\n        \n        if let resourceType = resourceType , resourceType != String(describing: LayerResourceType.image) {\n            components.append(resourceType)\n        }\n        if let type = type , type != String(describing: CLDType.upload) {\n            components.append(type)\n        }\n        \n        if !isResourceTypeTextual(resourceType) {\n            if let pubId = getFinalPublicId() , !pubId.isEmpty {\n                components.append(pubId.replacingOccurrences(of: \"/\", with: \":\"))\n            }\n        }\n        \n        return components\n    }\n    \n    // MARK: - Actions\n    \n    internal func asString() -> String? {\n        guard let components = self.getStringComponents() else {\n            return nil\n        }\n        \n        return components.joined(separator: \":\")\n    }\n    \n    // MARK: - Params\n    \n    @objc public enum LayerResourceType: Int, CustomStringConvertible {\n        case image, raw, auto, text, subtitles, video, fetch\n        \n        public var description: String {\n            get {\n                switch self {\n                case .image:        return \"image\"\n                case .raw:          return \"raw\"\n                case .auto:         return \"auto\"\n                case .text:         return \"text\"\n                case .subtitles:    return \"subtitles\"\n                case .video:        return \"video\"\n                case .fetch:        return \"fetch\"\n\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Layers/CLDSubtitlesLayer.swift",
    "content": "//\n//  CLDSubtitlesLayer.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDSubtitlesLayer: CLDTextLayer {\n    \n    // MARK: - Init\n    \n    /**\n     Initialize a CLDLayer instance.\n     \n     -returns: The new CLDLayer instance.\n     */\n    public override init() {\n        super.init()\n        resourceType = String(describing: LayerResourceType.subtitles)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Layers/CLDTextLayer.swift",
    "content": "//\n//  CLDTextLayer.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDTextLayer: CLDLayer {\n    \n    internal var text: String?\n    internal var fontFamily: String?\n    internal var fontSize: String?\n    internal var fontStyle: String?\n    internal var fontWeight: String?\n    internal var textDecoration: String?\n    internal var textAlign: String?\n    internal var stroke: String?\n    internal var letterSpacing: String?\n    internal var lineSpacing: String?\n    internal var fontAntialiasing: String?\n    internal var fontHinting: String?\n    \n    // MARK: - Init\n    \n    /**\n     Initialize a CLDTextLayer instance.\n     \n     -returns: The new CLDTextLayer instance.\n     */\n    public override init() {        \n        super.init()\n        resourceType = String(describing: LayerResourceType.text)\n    }\n    \n    // MARK: - Set Values\n    \n    \n    /**\n     Add a text caption layer.\n     \n     - parameter text:          The text to use as a caption layer.\n     \n     - returns:                 The same instance of CLDTextLayer.\n     */\n    open func setText(text: String) -> CLDTextLayer {\n        self.text = text\n        return self\n    }\n    \n    /**\n     Set the name of a font family. e.g. `arial`.\n     \n     - parameter fontFamily:    The layer font family.\n     \n     - returns:                 The same instance of CLDTextLayer.\n     */\n    open func setFontFamily(fontFamily: String) -> CLDTextLayer {\n        self.fontFamily = fontFamily\n        return self\n    }\n    \n    /**\n     Set the font size in pixels. e.g. 12.\n     \n     - parameter fontSize:      The layer font size.\n     \n     - returns:                 The same instance of CLDTextLayer.\n     */\n    @objc(setFontSizeFromInt:)\n    open func setFontSize(_ fontSize: Int) -> CLDTextLayer {\n        return setFontSize(String(fontSize))\n    }\n    \n    /**\n     Set the font size in pixels. e.g. 12.\n     \n     - parameter fontSize:      The layer font size.\n     \n     - returns:                 The same instance of CLDTextLayer.\n     */\n    @objc(setFontSizeFromString:)\n    open func setFontSize(_ fontSize: String) -> CLDTextLayer {\n        self.fontSize = fontSize\n        return self\n    }\n    \n    /**\n     Set the font style.\n     \n     - parameter fontStyle:     The layer font style.\n     \n     - returns:                 The same instance of CLDTextLayer.\n     */\n    @objc(setFontStyleFromLayerFontStyle:)\n    open func setFontStyle(_ fontStyle: CLDFontStyle) -> CLDTextLayer {\n        return setFontStyle(String(describing: fontStyle))\n    }\n    \n    /**\n     Set the font style. Possible values: normal (default value) or italic. e.g., italic\n     \n     - parameter fontStyle:     The layer font style.\n     \n     - returns:                 The same instance of CLDTextLayer.\n     */\n    @objc(setFontStyleFromString:)\n    open func setFontStyle(_ fontStyle: String) -> CLDTextLayer {\n        self.fontStyle = fontStyle\n        return self\n    }\n    \n    /**\n     Set the text weight.\n     \n     - parameter fontWeight:    The layer font weight.\n     \n     - returns:                 The same instance of CLDTextLayer.\n     */\n    @objc(setFontWeightFromLayerFontWeight:)\n    open func setFontWeight(_ fontWeight: CLDFontWeight) -> CLDTextLayer {\n        return setFontWeight(String(describing: fontWeight))\n    }\n    \n    /**\n     Set the text weight. Possible values: normal (default value) or bold.\n     \n     - parameter fontWeight:    The layer font weight.\n     \n     - returns:                 The same instance of CLDTextLayer.\n     */\n    @objc(setFontWeightFromString:)\n    open func setFontWeight(_ fontWeight: String) -> CLDTextLayer {\n        self.fontWeight = fontWeight\n        return self\n    }\n    \n    /**\n     Set the text decoration. Possible values: none (default value), underline or strikethrough.\n     \n     - parameter textDecoration:    The layer text Decoration.\n     \n     - returns:                     The same instance of CLDTextLayer.\n     */\n    @objc(setTextDecorationString:)\n    open func setTextDecoration(_ textDecoration: String) -> CLDTextLayer {\n        self.textDecoration = textDecoration\n        return self\n    }\n    \n    /**\n     Set the text alignment. Possible values: left (default value), center, right, end, start or justify.\n     \n     - parameter textAlign:     The layer text alignment.\n     \n     - returns:                 The same instance of CLDTextLayer.\n     */\n    @objc(setTextAlignString:)\n    open func setTextAlign(_ textAlign: String) -> CLDTextLayer {\n        self.textAlign = textAlign\n        return self\n    }\n    \n    /**\n     Set the font stroke (border).\n     Possible values: none (default value) or stroke.\n     Set the color and weight of the stroke with the border parameter.\n     \n     - parameter stroke:        The layer text stroke.\n     \n     - returns:                 The same instance of CLDTextLayer.\n     */\n    @objc(setStrokeString:)\n    open func setStroke(_ stroke: String) -> CLDTextLayer {\n        self.stroke = stroke\n        return self\n    }\n    \n    /**\n     Set the spacing between the letters in pixels. Can be a positive or negative.\n     \n     - parameter letterSpacing:         The layer letter Spacing.\n     \n     - returns:                         The same instance of CLDTextLayer.\n     */\n    @objc(setLetterSpacingFromInt:)\n    open func setLetterSpacing(_ letterSpacing: Int) -> CLDTextLayer {\n        return setLetterSpacing(String(letterSpacing))\n    }\n    \n    /**\n     Set the spacing between the letters in pixels. Can be a positive or negative.\n     \n     - parameter letterSpacing:         The layer letter Spacing.\n     \n     - returns:                         The same instance of CLDTextLayer.\n     */\n    @objc(setLetterSpacingFromFloat:)\n    open func setLetterSpacing(_ letterSpacing: Float) -> CLDTextLayer {\n        return setLetterSpacing(letterSpacing.cldFloatFormat())\n    }\n    \n    /**\n     Set the spacing between the letters in pixels. Can be a positive or negative.\n     \n     - parameter letterSpacing:         The layer letter Spacing.\n     \n     - returns:                         The same instance of CLDTextLayer.\n     */\n    @objc(setLetterSpacingString:)\n    open func setLetterSpacing(_ letterSpacing: String) -> CLDTextLayer {\n        self.letterSpacing = letterSpacing\n        return self\n    }\n    \n    /**\n     Set the spacing between the lines in pixels (only relevant for multi-line text). Can be a positive or negative.\n     \n     - parameter lineSpacing:           The layer line Spacing.\n     \n     - returns:                         The same instance of CLDTextLayer.\n     */\n    @objc(setLineSpacingFromInt:)\n    open func setLineSpacing(_ lineSpacing: Int) -> CLDTextLayer {\n        return setLineSpacing(String(describing: letterSpacing))\n    }\n    \n    /**\n     Set the spacing between the lines in pixels (only relevant for multi-line text). Can be a positive or negative.\n     \n     - parameter lineSpacing:           The layer line Spacing.\n     \n     - returns:                         The same instance of CLDTextLayer.\n     */\n    @objc(setLineSpacingFromFloat:)\n    open func setLineSpacing(_ lineSpacing: Float) -> CLDTextLayer {\n        return setLineSpacing(lineSpacing.cldFloatFormat())\n    }\n    \n    /**\n     Set the spacing between the lines in pixels (only relevant for multi-line text). Can be a positive or negative.\n     \n     - parameter lineSpacing:           The layer line Spacing.\n     \n     - returns:                         The same instance of CLDTextLayer.\n     */\n    @objc(setLineSpacingString:)\n    open func setLineSpacing(_ lineSpacing: String) -> CLDTextLayer {\n        self.lineSpacing = lineSpacing\n        return self\n    }\n    \n    /**\n     Set the antialiasing of the text layer rendering\n     \n     - parameter antialiasing:          The antialiasing method\n     \n     - returns:                         The same instance of CLDTextLayer.\n     */\n    @objc(setFontAntialiasingString:)\n    open func setFontAntialiasing(_ antialiasing: String) -> CLDTextLayer {\n        self.fontAntialiasing = antialiasing\n        return self\n    }\n    \n    /**\n     Set the antialiasing of the text layer rendering\n     \n     - parameter antialiasing:          The antialiasing method\n     \n     - returns:                         The same instance of CLDTextLayer.\n     */\n    open func setFontAntialiasing(_ antialiasing: CLDFontAntialiasing) -> CLDTextLayer {\n        self.fontAntialiasing = antialiasing.rawValue\n        return self\n    }\n    \n    /**\n     Set the text rendering hinting\n     \n     - parameter hinting:          The hinting method\n     \n     - returns:                    The same instance of CLDTextLayer.\n     */\n    @objc (setFontHintingString:)\n    open func setFontHinting(_ hinting: String) -> CLDTextLayer{\n        self.fontHinting = hinting\n        return self\n    }\n    \n    /**\n     Set the text rendering hinting\n     \n     - parameter hinting:          The hinting method\n     \n     - returns:                    The same instance of CLDTextLayer.\n     */\n    open func setFontHinting(_ hinting: CLDFontHinting) -> CLDTextLayer{\n        self.fontHinting = hinting.rawValue\n        return self\n    }\n    \n    // MARK: - Actions\n    \n    internal override func getStringComponents() -> [String]? {\n        \n        if (text == nil || text!.isEmpty) && (publicId == nil || publicId!.isEmpty) {\n            printLog(.error, text: \"Must supply either text or publicId\")\n            return nil\n        }\n        \n        guard var components = super.getStringComponents() else {\n            return nil\n        }\n        \n        let optionalTextParams = getOptionalTextPropertiesArray()\n        let mandatoryTextParams = getMandatoryTextPropertiesArray()\n        if optionalTextParams.isEmpty {\n            if !mandatoryTextParams.isEmpty {\n                components.append(mandatoryTextParams.joined(separator: \"_\"))\n            }\n        }\n        else if !mandatoryTextParams.isEmpty {\n            let textProperties = mandatoryTextParams + optionalTextParams\n            components.append(textProperties.joined(separator: \"_\"))\n        }\n        else  {\n            printLog(.error, text: \"Must supply fontSize and fontFamily for text layer\")\n            return nil\n        }\n        \n        if let publicId = publicId , !publicId.isEmpty {\n            components.append(publicId.replacingOccurrences(of: \"/\", with: \":\"))\n        }\n        if let text = text , !text.isEmpty {\n            if let text = text.cldSmartEncodeUrl() {\n                var textToAdd = text.replacingOccurrences(of: \"%2C\", with: \"%252C\")\n                textToAdd = textToAdd.replacingOccurrences(of: \"/\", with: \"%252F\")\n                components.append(textToAdd)\n            }\n        }\n        \n        return components\n    }\n    \n    //MARK: - Private\n    \n    fileprivate func getOptionalTextPropertiesArray() -> [String] {\n        var properties: [String] = []\n        if let fontWeight = fontWeight , fontWeight != \"normal\" {\n            properties.append(fontWeight)\n        }\n        if let fontStyle = fontStyle , fontStyle != \"normal\" {\n            properties.append(fontStyle)\n        }\n        if let antialiasing = fontAntialiasing, !antialiasing.isEmpty {\n            properties.append(\"antialias_\\(antialiasing)\")\n        }\n        if let hinting = fontHinting, !hinting.isEmpty {\n            properties.append(\"hinting_\\(hinting)\")\n        }\n        if let textDecoration = textDecoration , textDecoration != \"none\" {\n            properties.append(textDecoration)\n        }\n        if let stroke = stroke , stroke != \"none\" {\n            properties.append(stroke)\n        }\n        if let textAlign = textAlign , !textAlign.isEmpty {\n            properties.append(textAlign)\n        }\n        if let letterSpacing = letterSpacing , !letterSpacing.isEmpty {\n            properties.append(\"letter_spacing_\\(letterSpacing)\")\n        }\n        if let lineSpacing = lineSpacing , !lineSpacing.isEmpty {\n            properties.append(\"line_spacing_\\(lineSpacing)\")\n        }\n        \n        return properties\n    }\n    \n    fileprivate func getMandatoryTextPropertiesArray() -> [String] {\n        var properties: [String] = []\n        \n        if let fontSize = fontSize {\n            properties.insert(fontSize, at: 0)\n        }\n        \n        if let fontFamily = fontFamily {\n            properties.insert(fontFamily, at: 0)\n        }\n        \n        return properties\n    }\n    \n    /// Text layer font antialiasing methods\n    public enum CLDFontAntialiasing: String {\n        /// Use a bi-level alpha mask.\n        case NONE = \"none\"\n        \n        /// Perform single-color antialiasing. For example, using shades of gray for black text on a white background.\n        case GRAY = \"gray\"\n        \n        /// Perform antialiasing by taking advantage of the order of subpixel elements on devices such as LCD panels.\n        case SUBPIXEL = \"subpixel\"\n        \n        /// Some antialiasing is performed, but speed is prioritized over quality.\n        case FAST = \"fast\"\n        \n        /// Antialiasing that balances quality and performance.\n        case GOOD = \"good\"\n        \n        /// Renders at the highest quality, sacrificing speed if necessary.\n        case BEST = \"best\"\n    }\n    \n    /// Text layer font hinting methods\n    public enum CLDFontHinting: String {\n        /// Do not hint outlines.\n        case NONE = \"none\"\n        \n        /// Hint outlines slightly to improve contrast while retaining good fidelity to the original shapes.\n        case SLIGHT = \"slight\"\n        \n        /// Hint outlines with medium strength, providing a compromise between fidelity to the original shapes and contrast.\n        case MEDIUM = \"medium\"\n        \n        /// Hint outlines to the maximize contrast.\n        case FULL = \"full\"\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/RequestParams/CLDRequestParams.swift",
    "content": "//\n//  CLDRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The CLDRequestParams class is a base class for all different request params object.\n It holds a dictionary of the actual params, the request's resource type, the request signature for signing a request using an externaly generated signature, and the subclass' representing action.\n*/\n@objcMembers open class CLDRequestParams: NSObject {\n\n    /**\n     A dictionary of the params to be sent as part of the request.\n    */\n    internal var params: [String : Any]\n    \n    /**\n     The request's resource type, if set it will be part of the request URL. On most cases defaults to \"image\".\n     */\n    internal var resourceType: String?\n    \n    /**\n     The request signature for signing a request using an externally generated signature. if no signature is assigned, the SDK will sign the request using the configured API secret.\n     */\n    internal var signature: CLDSignature?\n    \n    /**\n     Override config apiKey with this value.\n     */\n    internal var apiKey: String?\n    \n    internal override init() {\n        apiKey = nil\n        signature = nil\n        resourceType = nil\n        params = [:]\n        super.init()\n    }\n    \n    //MARK: - Set Param\n    \n    /**\n    A generic setter to manualy set a param.\n    \n    - parameter key:                The key of parameter to set.\n    - parameter value:              The parameter value.\n    \n    - returns:                     The same instance of CLDRequestParams.\n    \n    */\n    @discardableResult\n    open func setParam(_ key: String, value: Any?) -> Self {\n        params[key] = value\n        return self\n    }\n\n    @discardableResult\n    @objc(setResourceTypeFromUrlResourceType:)\n    open func setResourceType(_ resourceType: CLDUrlResourceType) -> Self {\n        return setResourceType(String(describing: resourceType))\n    }\n\n    @discardableResult\n    @objc(setResourceTypeFromString:)\n    open func setResourceType(_ resourceType: String) -> Self {\n        self.resourceType = resourceType\n        return self\n    }\n\n    @discardableResult\n    @objc(setSignatureWithSignature:)\n    open func setSignature(_ signature: CLDSignature) -> Self {\n        self.signature = signature\n        return self\n    }\n    \n    @discardableResult\n    @objc(setApiKeyWithKey:)\n    open func setApiKey(_ apiKey: String) -> Self {\n        self.apiKey = apiKey\n        return self\n    }\n    \n    // MARK: - Get Param\n    \n    /**\n     A generic getter to retrieve a param for a given key.\n     \n     - parameter key:               The key of the parameter to retrieve.\n     \n     - returns:                     The same instance of CLDRequestParams.\n     \n     */\n    open func getParam(_ key: String) -> Any? {\n        return params[key]\n    }\n    \n    internal func merge(_ other: CLDRequestParams?) {\n        if let other = other {\n            self.signature = other.signature\n            self.resourceType = other.resourceType\n            self.params.cldMerge(other.params)\n            self.apiKey = other.apiKey\n        }\n    }\n    \n    internal func setTimeout(from config: CLDConfiguration) {\n        guard let timeout = config.timeout else { return }\n\n        setParam(CLDConfiguration.ConfigParam.Timeout.description, value: timeout)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/RequestParams/Helpers/CLDRequestParamsHelpers.swift",
    "content": "//\n//  CLDRequestParamsHelpers.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport CoreGraphics\n\n// MARK: - CLDSignature\n\n/**\nThe CLDSignature class represents a signature used to sign a URL request.\n*/\n@objcMembers open class CLDSignature: NSObject {\n        \n    public let signature: String\n    public let timestamp: NSNumber\n    \n    public init(signature: String, timestamp: NSNumber) {\n        self.signature = signature\n        self.timestamp = timestamp\n        super.init()\n    }\n    \n    \n    internal enum SignatureParam: String, CustomStringConvertible {\n        case Signature =        \"signature\"\n        case Timestamp =        \"timestamp\"\n        \n        var description: String {\n            get {\n                switch self {\n                case .Signature: return \"signature\"\n                case .Timestamp: return \"timestamp\"\n                }\n            }\n        }\n    }\n}\n\n\n// MARK: - CLDAccessControlRule\n\n/**\n The CLDAccessControlRule class represents a single access control rule for upload/update API\n */\n@objcMembers open class CLDAccessControlRule: NSObject, Codable {\n    // MARK: Properties\n\n    internal var start: Date?\n    internal var end: Date?\n    internal var accessType: CLDAccessType\n\n    // MARK: Init\n\n    /**\n     Initializes the CLDAccessControlRule\n\n     - parameter accessType:    The access type for this rule\n     - parameter start:         The start time for the rule\n     - parameter end:           The end time for the rule\n\n     - returns:                 A new CLDaccessControlRule instance.\n     */\n    internal init(accessType: CLDAccessType, start: Date? = nil, end: Date? = nil) {\n        self.accessType = accessType\n        self.start = start\n        self.end = end\n    }\n\n    // MARK: Static builders\n\n    /**\n    Get a new instance of CLDAccessControlRule with token strategy\n    */\n    public static func token()-> CLDAccessControlRule {\n        return CLDAccessControlRule(accessType: CLDAccessType.token)\n    }\n\n    /**\n    Get a new instance of CLDAccessControlRule with anonymous strategy\n\n    - parameter start:    The start date for the rule\n\n    */\n    public static func anonymous(start: Date)-> CLDAccessControlRule {\n        return CLDAccessControlRule(accessType: CLDAccessType.anonymous, start: start)\n    }\n\n    /**\n    Get a new instance of CLDAccessControlRule with anonymous strategy\n\n    - parameter end:    The end date for the rule\n\n    */\n    public static func anonymous(end: Date)-> CLDAccessControlRule {\n        return CLDAccessControlRule(accessType: CLDAccessType.anonymous, end: end)\n    }\n\n    /**\n    Get a new instance of CLDAccessControlRule with anonymous strategy\n\n    - parameter start:    The start date for the rule\n    - parameter end:      The end date for the rule\n\n    */\n    public static func anonymous(start: Date, end: Date)-> CLDAccessControlRule {\n        return CLDAccessControlRule(accessType: CLDAccessType.anonymous, start: start, end: end)\n    }\n\n    // MARK: Encodable\n\n    enum CodingKeys: String, CodingKey {\n        case start\n        case end\n        case accessType = \"access_type\"\n    }\n\n    // MARK: Equatable\n\n    static func == (lhs: CLDAccessControlRule, rhs: CLDAccessControlRule) -> Bool {\n        return lhs.accessType == rhs.accessType && lhs.start == rhs.start && lhs.end == rhs.end\n    }\n}\n\npublic enum CLDAccessType : String, Codable {\n    case anonymous, token\n}\n\n// MARK: - CLDCoordinate\n\n/**\nThe CLDCoordinate class represents a rectangle area on an asset.\n*/\n@objcMembers open class CLDCoordinate: NSObject {\n    \n    let rect: CGRect\n    \n    var x: Float {\n        return Float(rect.origin.x)\n    }\n    \n    var y: Float {\n        return Float(rect.origin.y)\n    }\n    \n    var width: Float {\n        return Float(rect.width)\n    }\n    \n    var height: Float {\n        return Float(rect.height)\n    }\n    \n    // MARK: Init\n    \n    /**\n    Initializes the CLDCoordinate using a CGRect.\n    \n    - parameter rect:   The rectangle representing an area on the asset.\n    \n    - returns:          A new CLDCoordinate instance.\n    */\n    public init(rect: CGRect) {\n        self.rect = rect\n    }\n    \n    open override var description: String {\n        get {\n            var components: [String] = []\n            components.append(x.cldFormat(f: \".0\"))\n            components.append(y.cldFormat(f: \".0\"))\n            components.append(width.cldFormat(f: \".0\"))\n            components.append(height.cldFormat(f: \".0\"))\n            return components.joined(separator: \",\")\n        }\n    }\n}\n\n\n\n// MARK: - CLDResponsiveBreakpoints\n\n/**\nThe CLDResponsiveBreakpoints class describe the settings available for configuring responsive breakpoints.\nResponsive breakpoints is used to request Cloudinary to automatically find the best breakpoints.\n*/\n@objcMembers open class CLDResponsiveBreakpoints: NSObject {\n    internal var params: [String: AnyObject] = [:]\n    \n    // MARK - Init\n    \n    /**\n    Initializes a CLDResponsiveBreakpoints instance.\n    \n    - parameter createDerived:      If true, create and keep the derived assets of the selected breakpoints during the API call.\n                                    If false, assets generated during the analysis process are thrown away.\n    \n    - returns:                      A new CLDResponsiveBreakpoints instance.\n    */\n    public init(createDerived: Bool) {\n        super.init()\n        setParam(ResponsiveBreakpointsParams.CreateDerived.rawValue, value: createDerived as AnyObject?)\n    }\n\n    // MARK - Set Param\n\n    /**\n    Set the base transformation to first apply to the image before finding the best breakpoints.\n    \n    - parameter transformation:     The transformation to apply.\n    \n    - returns:                      The same CLDResponsiveBreakpoints instance.\n    */\n    open func setTransformations(_ transformation: CLDTransformation) -> Self {\n        return setParam(ResponsiveBreakpointsParams.Transformation.rawValue, value: transformation.asString() as AnyObject)\n    }\n    \n    /**\n     Set the maximum width needed for this asset. \n     If specifying a width bigger than the original asset, the width of the original asset is used instead. default is 1000.\n     \n     - parameter maxWidth:          The max width to set.\n     \n     - returns:                      The same CLDResponsiveBreakpoints instance.\n     */\n    open func setMaxWidth(_ maxWidth: Int) -> Self {\n        return setParam(ResponsiveBreakpointsParams.MaxWidth.rawValue, value: maxWidth as AnyObject?)\n    }\n    \n    /**\n     Set the minimum width needed for this asset. default is 50.\n     \n     - parameter minWidth:          The min width to set.\n     \n     - returns:                      The same CLDResponsiveBreakpoints instance.\n     */\n    open func setMinWidth(_ minWidth: Int) -> Self {\n        return setParam(ResponsiveBreakpointsParams.MinWidth.rawValue, value: minWidth as AnyObject?)\n    }\n    \n    /**\n     Set the minimum number of bytes between two consecutive breakpoints (assets). default is 20000.\n     \n     - parameter bytesStep:          The bytes step to set.\n     \n     - returns:                      The same CLDResponsiveBreakpoints instance.\n     */\n    open func setBytesStep(_ bytesStep: Int) -> Self {\n        return setParam(ResponsiveBreakpointsParams.BytesStep.rawValue, value: bytesStep as AnyObject?)\n    }\n    \n    /**\n     Set the maximum number of breakpoints to find, between 3 and 200. \n     This means that there might be size differences bigger than the given bytes_step value between consecutive assets. default is 20.\n     \n     - parameter maxImages:          The max images to set.\n     \n     - returns:                      The same CLDResponsiveBreakpoints instance.\n     */\n    open func setMaxImages(_ maxImages: Int) -> Self {\n        return setParam(ResponsiveBreakpointsParams.MaxImages.rawValue, value: maxImages as AnyObject?)\n    }\n\n    /**\n     Set the format of the resulting images.\n\n     - parameter format:          The format to set.\n\n     - returns:                   The same CLDResponsiveBreakpoints instance.\n     */\n    open func setFormat(_ format: String) -> Self {\n        return setParam(ResponsiveBreakpointsParams.Format.rawValue, value: format as AnyObject)\n    }\n\n    @discardableResult\n    open func setParam(_ key: String, value: AnyObject?) -> Self {\n        params[key] = value\n        return self\n    }\n\n    open override var description: String {\n        get {\n            var components: [String] = []\n            for param in params {\n                if param.value is Int || param.value is Bool {\n                    components.append(\"\\\"\\(param.key)\\\":\\(param.value)\")\n                } else {\n                    components.append(\"\\\"\\(param.key)\\\":\\\"\\(param.value)\\\"\")\n                }\n            }\n\n            return \"{\\(components.joined(separator: \",\"))}\"\n        }\n    }\n\n    \n    fileprivate enum ResponsiveBreakpointsParams: String, CustomStringConvertible {\n        case CreateDerived =                \"create_derived\"\n        case Transformation =               \"transformation\"\n        case MaxWidth =                     \"max_width\"\n        case MinWidth =                     \"min_width\"\n        case BytesStep =                    \"bytes_step\"\n        case MaxImages =                    \"max_images\"\n        case Format =                       \"format\"\n\n        var description: String {\n            get {\n                switch self {\n                case .CreateDerived:         return \"create_derived\"\n                case .Transformation:        return \"transformation\"\n                case .MaxWidth:              return \"max_width\"\n                case .MinWidth:              return \"min_width\"\n                case .BytesStep:             return \"bytes_step\"\n                case .MaxImages:             return \"max_images\"\n                case .Format:                return \"format\"\n                }\n            }\n        }\n    }\n    \n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Requests/CLDRequest.swift",
    "content": "//\n//  CLDRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The `CLDRequest` object is returned when creating a network request using one of Cloudinary's API calls.\n It allows the options to add a response closure to be called once the request has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n@objcMembers open class CLDRequest: NSObject {\n    \n    \n    internal var networkRequest: CLDNetworkDataRequest\n    \n    internal init(networkRequest: CLDNetworkDataRequest) {\n        self.networkRequest = networkRequest\n    }\n    \n    \n    // MARK: - Public\n    \n    /**\n     Resume the request.\n     */\n    open func resume() {\n       networkRequest.resume()\n    }\n    \n    /**\n     Suspend the request.\n     */\n    open func suspend() {\n        networkRequest.suspend()\n    }\n    \n    /**\n     Cancel the request.\n     */\n    open func cancel() {\n        networkRequest.cancel()\n    }\n    \n    //MARK: Handlers\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDRequest.\n     */\n    @discardableResult\n    open func responseRaw(_ completionHandler: @escaping (_ response: Any?, _ error: NSError?) -> ()) -> CLDRequest {\n        networkRequest.response(completionHandler)\n        return self\n    }        \n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/CLDBaseResult.swift",
    "content": "//\n//  CLDBaseResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDBaseResult: NSObject {\n    \n    open fileprivate(set) var resultJson: [String : AnyObject]\n    \n    \n    // MARK: - Init\n    \n    internal init(json: [String : AnyObject]) {\n        resultJson = json\n    }    \n    \n    // MARK: - Private Helpers\n    \n    internal func getParam(_ param: CommonResultKeys) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/AccessibilityAnalysis/CLDAccessibilityAnalysisResult.swift",
    "content": "//\n//  CLDAccessibilityAnalysisResult.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDAccessibilityAnalysisResult: CLDBaseResult {\n    \n    open var colorblindAccessibilityScore: Double? {\n        guard let accessibilityScore = getParam(.colorblindAccessibilityScore) as? Double else { return nil }\n        \n        return accessibilityScore\n    }\n    open var colorblindAccessibilityAnalysis: CLDColorblindAccessibilityAnalysisResult? {\n        guard let accessibilityAnalysis = getParam(.colorblindAccessibilityAnalysis) as? [String: AnyObject] else { return nil }\n        \n        return CLDColorblindAccessibilityAnalysisResult(json: accessibilityAnalysis)\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDAccessibilityAnalysisResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDAccessibilityAnalysisResultKey: CustomStringConvertible {\n        case colorblindAccessibilityScore, colorblindAccessibilityAnalysis\n        \n        var description: String {\n            switch self {\n            case .colorblindAccessibilityScore   : return \"colorblind_accessibility_score\"\n            case .colorblindAccessibilityAnalysis: return \"colorblind_accessibility_analysis\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/AccessibilityAnalysis/CLDColorblindAccessibilityAnalysisResult.swift",
    "content": "//\n//  CLDColorblindAccessibilityAnalysisResult.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDColorblindAccessibilityAnalysisResult: CLDBaseResult {\n    \n    open var distinctColors: Double? {\n        guard let distinctColors = getParam(.distinctColors) as? Double else { return nil }\n        \n        return distinctColors\n    }\n    open var distinctEdges: Double? {\n        guard let distinctEdges = getParam(.distinctEdges) as? Double else { return nil }\n        \n        return distinctEdges\n    }\n    open var mostIndistinctPair: [String]? {\n        guard let mostIndistinctPair = getParam(.mostIndistinctPair) as? [String] else { return nil }\n        \n        return mostIndistinctPair\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDColorblindAccessibilityAnalysisResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDColorblindAccessibilityAnalysisResultKey: CustomStringConvertible {\n        case distinctColors, distinctEdges, mostIndistinctPair\n        \n        var description: String {\n            switch self {\n            case .distinctColors    : return \"distinct_colors\"\n            case .distinctEdges     : return \"distinct_edges\"\n            case .mostIndistinctPair: return \"most_indistinct_pair\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDBoundingBox.swift",
    "content": "//\n//  CLDBoundingBox.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\nimport Foundation\nimport CoreGraphics\n\n@objcMembers open class CLDBoundingBox: CLDBaseResult {\n    \n    open var topLeft: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDBoundingBoxJsonKey.topLeft))\n    }\n    \n    open var size: CGSize? {\n        return CLDBoundingBox.parseSize(resultJson, key: String(describing: CLDBoundingBoxJsonKey.size))\n    }\n    \n    internal static func parsePoint(_ json: [String : AnyObject], key: String) -> CGPoint? {\n        guard let\n            point = json[key] as? [String : Double],\n            let x = point[CommonResultKeys.x.description],\n            let y = point[CommonResultKeys.y.description] else {\n                return nil\n        }\n        return CGPoint(x: CGFloat(x), y: CGFloat(y))\n    }\n    \n    internal static func parseSize(_ json: [String : AnyObject], key: String) -> CGSize? {\n        guard let\n            point = json[key] as? [String : Double],\n            let width = point[CommonResultKeys.width.description],\n            let height = point[CommonResultKeys.height.description] else {\n                return nil\n        }\n        return CGSize(width: CGFloat(width), height: CGFloat(height))\n    }\n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: CLDBoundingBoxJsonKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDBoundingBoxJsonKey: CustomStringConvertible {\n        case topLeft, size\n        \n        var description: String {\n            switch self {\n            case .topLeft:  return \"tl\"\n            case .size:     return \"size\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDDetection.swift",
    "content": "//\n//  CLDDetection.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDDetection: CLDBaseResult {\n    \n    open var rekognitionFace: CLDRekognitionFace? {\n        guard let rekognitionFace = getParam(.rekognitionFace) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDRekognitionFace(json: rekognitionFace)\n    }\n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: CLDDetectionKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDDetectionKey: CustomStringConvertible {\n        case rekognitionFace\n        \n        var description: String {\n            switch self {\n            case .rekognitionFace:           return \"rekognition_face\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDFace.swift",
    "content": "//\n//  CLDFace.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport CoreGraphics\n\n@objcMembers open class CLDFace: CLDBaseResult {\n    \n    open var boundingBox: CLDBoundingBox? {\n        guard let bb = getParam(.boundingBox) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDBoundingBox(json: bb)\n    }\n    \n    open var confidence: Double? {\n        return getParam(.confidence) as? Double\n    }\n    \n    open var age: Double? {\n        return getParam(.age) as? Double\n    }\n    \n    open var smile: Double? {\n        return getParam(.smile) as? Double\n    }\n    \n    open var glasses: Double? {\n        return getParam(.glasses) as? Double\n    }\n    \n    open var sunglasses: Double? {\n        return getParam(.sunglasses) as? Double\n    }\n    \n    open var beard: Double? {\n        return getParam(.beard) as? Double\n    }\n    \n    open var mustache: Double? {\n        return getParam(.mustache) as? Double\n    }\n    \n    open var eyeClosed: Double? {\n        return getParam(.eyeClosed) as? Double\n    }\n    \n    open var mouthOpenWide: Double? {\n        return getParam(.mouthOpenWide) as? Double\n    }\n    \n    open var beauty: Double? {\n        return getParam(.beauty) as? Double\n    }\n    \n    open var gender: Double? {\n        return getParam(.gender) as? Double\n    }\n    \n    open var race: [String : Double]? {\n        return getParam(.race) as? [String : Double]\n    }\n    \n    open var emotion: [String : Double]? {\n        return getParam(.emotion) as? [String : Double]\n    }\n    \n    open var quality: [String : Double]? {\n        return getParam(.quality) as? [String : Double]\n    }\n    \n    open var pose: [String : Double]? {\n        return getParam(.pose) as? [String : Double]\n    }\n    \n    open var eyeLeftPosition: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.eyeLeftPosition))\n    }\n    \n    open var eyeRightPosition: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.eyeRightPosition))\n    }\n    \n    open var eyeLeft_Left: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.eyeLeft_Left))\n    }\n    \n    open var eyeLeft_Right: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.eyeLeft_Right))\n    }\n    \n    open var eyeLeft_Up: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.eyeLeft_Up))\n    }\n    \n    open var eyeLeft_Down: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.eyeLeft_Down))\n    }\n    \n    open var eyeRight_Left: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.eyeRight_Left))\n    }\n    \n    open var eyeRight_Right: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.eyeRight_Right))\n    }\n    \n    open var eyeRight_Up: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.eyeRight_Up))\n    }\n    \n    open var eyeRight_Down: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.eyeRight_Down))\n    }\n    \n    open var nosePosition: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.nosePosition))\n    }\n    \n    open var noseLeft: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.noseLeft))\n    }\n    \n    open var noseRight: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.noseRight))\n    }\n    \n    open var mouthLeft: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.mouthLeft))\n    }\n    \n    open var mouthRight: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.mouthRight))\n    }\n    \n    open var mouthUp: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.mouthUp))\n    }\n    \n    open var mouthDown: CGPoint? {\n        return CLDBoundingBox.parsePoint(resultJson, key: String(describing: CLDFaceKey.mouthDown))\n    }\n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: CLDFaceKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDFaceKey: CustomStringConvertible {\n        case boundingBox, confidence, age, smile, glasses, sunglasses, beard, mustache, eyeClosed, mouthOpenWide, beauty, gender, race, emotion, quality, pose, eyeLeftPosition, eyeRightPosition, eyeLeft_Left, eyeLeft_Right, eyeLeft_Up, eyeLeft_Down, eyeRight_Left, eyeRight_Right, eyeRight_Up, eyeRight_Down, nosePosition, noseLeft, noseRight, mouthLeft, mouthRight, mouthUp, mouthDown\n        \n        var description: String {\n            switch self {\n            case .boundingBox:          return \"boundingbox\"\n            case .confidence:           return \"confidence\"\n            case .age:                  return \"age\"\n            case .smile:                return \"smile\"\n            case .glasses:              return \"glasses\"\n            case .sunglasses:           return \"sunglasses\"\n            case .beard:                return \"beard\"\n            case .mustache:             return \"mustache\"\n            case .eyeClosed:            return \"eye_closed\"\n            case .mouthOpenWide:        return \"mouth_open_wide\"\n            case .beauty:               return \"beauty\"\n            case .gender:               return \"sex\"\n            case .race:                 return \"race\"\n            case .emotion:              return \"emotion\"\n            case .quality:              return \"quality\"\n            case .pose:                 return \"pose\"\n            case .eyeLeftPosition:      return \"eye_left\"\n            case .eyeRightPosition:     return \"eye_right\"\n            case .eyeLeft_Left:         return \"e_ll\"\n            case .eyeLeft_Right:        return \"e_lr\"\n            case .eyeLeft_Up:           return \"e_lu\"\n            case .eyeLeft_Down:         return \"e_ld\"\n            case .eyeRight_Left:        return \"e_rl\"\n            case .eyeRight_Right:       return \"e_rr\"\n            case .eyeRight_Up:          return \"e_ru\"\n            case .eyeRight_Down:        return \"e_rd\"\n            case .nosePosition:         return \"nose\"\n            case .noseLeft:             return \"n_l\"\n            case .noseRight:            return \"n_r\"\n            case .mouthLeft:            return \"mouth_l\"\n            case .mouthRight:           return \"mouth_r\"\n            case .mouthUp:              return \"m_u\"\n            case .mouthDown:            return \"m_d\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDInfo.swift",
    "content": "//\n//  CLDInfo.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDInfo: CLDBaseResult {\n    \n    open var detection: CLDDetection? {\n        guard let detection = getParam(.detection) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDDetection(json: detection)\n    }\n    \n    open var ocr: CLDOcrResult? {\n        guard let ocr = getParam(.ocr) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDOcrResult(json: ocr)\n    }\n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: CLDInfoKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDInfoKey: CustomStringConvertible {\n        case detection, ocr\n        \n        var description: String {\n            switch self {\n            case .detection: return \"detection\"\n            case .ocr      : return \"ocr\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDAdvOcrResult.swift",
    "content": "//\n//  CLDAdvOcrResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDAdvOcrResult: CLDBaseResult {\n    \n    open var status: String? {\n        guard let status = getParam(.status) as? String else { return nil }\n        \n        return status\n    }\n    open var data: [CLDOcrDataResult]? {\n        guard let data = getParam(.data) as? [[String : AnyObject]] else { return nil }\n        \n        return data.compactMap{ CLDOcrDataResult(json: $0) }\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDAdvOcrResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDAdvOcrResultKey: CustomStringConvertible {\n        case status, data\n        \n        var description: String {\n            switch self {\n            case .status: return \"status\"\n            case .data  : return \"data\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrBlockResult.swift",
    "content": "//\n//  CLDOcrBlockResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrBlockResult: CLDBaseResult {\n    \n    open var boundingBox: CLDOcrBoundindBlockResult? {\n        guard let boundingBox = getParam(.boundingBox) as? [String : AnyObject]  else { return nil }\n        \n        return CLDOcrBoundindBlockResult(json: boundingBox)\n    }\n    open var property: CLDOcrPropertyResult? {\n        guard let property = getParam(.property) as? [String : AnyObject] else { return nil }\n        \n        return CLDOcrPropertyResult(json: property)\n    }\n    open var paragraphs: [CLDOcrParagraphResult]? {\n        guard let paragraphs = getParam(.paragraphs) as? [[String : AnyObject]] else { return nil }\n        \n        return paragraphs.compactMap({ CLDOcrParagraphResult(json: $0) })\n    }\n    open var blockType: String? {\n        guard let blockType = getParam(.blockType) as? String else { return nil }\n        \n        return blockType\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrBlockResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrBlockResultKey: CustomStringConvertible {\n        case boundingBox, property, paragraphs, blockType\n        \n        var description: String {\n            switch self {\n            case .boundingBox: return \"boundingBox\"\n            case .property   : return \"property\"\n            case .paragraphs : return \"paragraphs\"\n            case .blockType  : return \"blockType\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrBoundindBlockResult.swift",
    "content": "//\n//  CLDOcrBoundindBlockResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport CoreGraphics\n\n@objcMembers open class CLDOcrBoundindBlockResult: CLDBaseResult {\n\n    open var vertices: [CGPoint]? {\n        guard let vertices = getParam(.vertices) as? [[String : AnyObject]] else { return nil}\n        \n        return vertices.compactMap{\n            if let x = $0[\"x\"] as? NSNumber, let y = $0[\"y\"] as? NSNumber {\n               return CGPoint(x: x.intValue, y: y.intValue)\n            }\n            else {\n                return nil\n            }\n        }\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrBoundindBlockResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrBoundindBlockResultKey: CustomStringConvertible {\n        case vertices\n        \n        var description: String {\n            switch self {\n            case .vertices : return \"vertices\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrDataResult.swift",
    "content": "//\n//  CLDOcrDataResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrDataResult: CLDBaseResult {\n    \n    open var textAnnotations: [CLDOcrTextAnnotationResult]? {\n        guard let textAnnotations = getParam(.textAnnotations) as? [[String : AnyObject]] else { return nil }\n        \n        return textAnnotations.compactMap{ CLDOcrTextAnnotationResult(json: $0) }\n    }\n    open var fullTextAnnotation: CLDOcrFullTextAnnotationResult? {\n        guard let fullTextAnnotation = getParam(.fullTextAnnotation) as? [String : AnyObject] else { return nil }\n        \n        return CLDOcrFullTextAnnotationResult(json: fullTextAnnotation)\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrDataResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrDataResultKey: CustomStringConvertible {\n        case textAnnotations, fullTextAnnotation\n        \n        var description: String {\n            switch self {\n            case .textAnnotations    : return \"textAnnotations\"\n            case .fullTextAnnotation : return \"fullTextAnnotation\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrDetectedLanguagesResult.swift",
    "content": "//\n//  CLDOcrDetectedLanguagesResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrDetectedLanguagesResult: CLDBaseResult {\n    \n    open var languageCode: String? {\n        guard let languageCode = getParam(.languageCode) as? String else { return nil }\n        \n        return languageCode\n    }\n    open var confidence: Int? {\n        guard let confidence = getParam(.confidence) as? Int else { return nil }\n        \n        return confidence\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrDetectedLanguagesResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrDetectedLanguagesResultKey: CustomStringConvertible {\n        case languageCode, confidence\n        \n        var description: String {\n            switch self {\n            case .languageCode: return \"languageCode\"\n            case .confidence  : return \"confidence\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrFullTextAnnotationResult.swift",
    "content": "//\n//  CLDOcrFullTextAnnotationResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrFullTextAnnotationResult: CLDBaseResult {\n    \n    open var pages: [CLDOcrPageResult]? {\n        guard let pages = getParam(.pages) as? [[String : AnyObject]] else { return nil }\n        \n        return pages.compactMap({ CLDOcrPageResult(json: $0) })\n    }\n    open var text: String? {\n        guard let text = getParam(.text) as? String else { return nil }\n        \n        return text\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrFullTextAnnotationResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrFullTextAnnotationResultKey: CustomStringConvertible {\n        case pages, text\n        \n        var description: String {\n            switch self {\n            case .pages: return \"pages\"\n            case .text : return \"text\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrPageResult.swift",
    "content": "//\n//  CLDOcrPageResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrPageResult: CLDBaseResult {\n    \n    open var blocks: [CLDOcrBlockResult]? {\n        guard let blocks = getParam(.blocks) as? [[String : AnyObject]] else { return nil }\n        \n        return blocks.compactMap({ CLDOcrBlockResult(json: $0) })\n    }\n    open var property: CLDOcrPropertyResult? {\n        guard let property = getParam(.property) as? [String : AnyObject] else { return nil }\n        \n        return CLDOcrPropertyResult(json: property)\n    }\n    open var width: Int? {\n        guard let width = getParam(.pageWidth) as? Int else { return nil }\n        \n        return width\n    }\n    open var height: Int? {\n        guard let height = getParam(.pageHeight) as? Int else { return nil }\n        \n        return height\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrPageResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrPageResultKey: CustomStringConvertible {\n        case blocks, property, pageWidth, pageHeight\n        \n        var description: String {\n            switch self {\n            case .blocks    : return \"blocks\"\n            case .property  : return \"property\"\n            case .pageWidth : return \"width\"\n            case .pageHeight: return \"height\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrParagraphResult.swift",
    "content": "//\n//  CLDOcrParagraphResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrParagraphResult: CLDBaseResult {\n    \n    open var boundingBox: CLDOcrBoundindBlockResult? {\n        guard let boundingBox = getParam(.boundingBox) as? [String : AnyObject]  else { return nil }\n        \n        return CLDOcrBoundindBlockResult(json: boundingBox)\n    }\n    open var property: CLDOcrPropertyResult? {\n        guard let property = getParam(.property) as? [String : AnyObject] else { return nil }\n        \n        return CLDOcrPropertyResult(json: property)\n    }\n    open var words: [CLDOcrWordResult]? {\n        guard let words = getParam(.words) as? [[String : AnyObject]] else { return nil }\n        \n        return words.compactMap({ CLDOcrWordResult(json: $0) })\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrParagraphResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrParagraphResultKey: CustomStringConvertible {\n        case boundingBox, property, words\n        \n        var description: String {\n            switch self {\n            case .boundingBox: return \"boundingBox\"\n            case .property   : return \"property\"\n            case .words      : return \"words\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrPropertyResult.swift",
    "content": "//\n//  CLDOcrPropertyResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrPropertyResult: CLDBaseResult {\n    \n    open var detectedLanguages: [CLDOcrDetectedLanguagesResult]? {\n        guard let detectedLanguages = getParam(.detectedLanguages) as? [[String : AnyObject]] else { return nil }\n        \n        return detectedLanguages.compactMap({ CLDOcrDetectedLanguagesResult(json: $0) })\n    }\n   \n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrPropertyResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrPropertyResultKey: CustomStringConvertible {\n        case detectedLanguages\n        \n        var description: String {\n            switch self {\n            case .detectedLanguages: return \"detectedLanguages\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrResult.swift",
    "content": "//\n//  CLDOcrResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrResult: CLDBaseResult {\n    \n    open var advOcr: CLDAdvOcrResult? {\n        guard let advOcr = getParam(.advOcr) as? [String : AnyObject] else { return nil }\n        \n        return CLDAdvOcrResult(json: advOcr)\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrResultKey: CustomStringConvertible {\n        case advOcr\n        \n        var description: String {\n            switch self {\n            case .advOcr: return \"adv_ocr\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrSymbolResult.swift",
    "content": "//\n//  CLDOcrSymbolResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrSymbolResult: CLDBaseResult {\n    \n    open var boundingBox: CLDOcrBoundindBlockResult? {\n        guard let boundingBox = getParam(.boundingBox) as? [String : AnyObject]  else { return nil }\n        \n        return CLDOcrBoundindBlockResult(json: boundingBox)\n    }\n    open var property: CLDOcrPropertyResult? {\n        guard let property = getParam(.property) as? [String : AnyObject] else { return nil }\n        \n        return CLDOcrPropertyResult(json: property)\n    }\n    open var text: String? {\n        guard let text = getParam(.text) as? String else { return nil }\n        \n        return text\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrSymbolResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrSymbolResultKey: CustomStringConvertible {\n        case boundingBox, property, text\n        \n        var description: String {\n            switch self {\n            case .boundingBox: return \"boundingBox\"\n            case .property   : return \"property\"\n            case .text       : return \"text\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrTextAnnotationResult.swift",
    "content": "//\n//  CLDOcrTextAnnotationResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrTextAnnotationResult: CLDBaseResult {\n    \n    open var locale: String? {\n        guard let locale = getParam(.locale) as? String else { return nil }\n\n        return locale\n    }\n    open var textDescription: String? {\n        guard let textDescription = getParam(.description) as? String else { return nil }\n        \n        return textDescription\n    }\n    open var boundingBlock: CLDOcrBoundindBlockResult? {\n        guard let boundingBlock = getParam(.boundingPoly) as? [String : AnyObject] else { return nil }\n        \n        return CLDOcrBoundindBlockResult(json: boundingBlock)\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrTextAnnotationResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrTextAnnotationResultKey: CustomStringConvertible {\n        case locale, description, boundingPoly\n        \n        var description: String {\n            switch self {\n            case .locale       : return \"locale\"\n            case .description  : return \"description\"\n            case .boundingPoly : return \"boundingPoly\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDOcr/CLDOcrWordResult.swift",
    "content": "//\n//  CLDOcrWordResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDOcrWordResult: CLDBaseResult {\n    \n    open var boundingBox: CLDOcrBoundindBlockResult? {\n        guard let boundingBox = getParam(.boundingBox) as? [String : AnyObject]  else { return nil }\n        \n        return CLDOcrBoundindBlockResult(json: boundingBox)\n    }\n    open var property: CLDOcrPropertyResult? {\n        guard let property = getParam(.property) as? [String : AnyObject] else { return nil }\n        \n        return CLDOcrPropertyResult(json: property)\n    }\n    open var symbols: [CLDOcrSymbolResult]? {\n        guard let symbols = getParam(.symbols) as? [[String : AnyObject]] else { return nil }\n        \n        return symbols.compactMap({ CLDOcrSymbolResult(json: $0) })\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDOcrWordResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDOcrWordResultKey: CustomStringConvertible {\n        case boundingBox, property, symbols\n        \n        var description: String {\n            switch self {\n            case .boundingBox: return \"boundingBox\"\n            case .property   : return \"property\"\n            case .symbols    : return \"symbols\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDQualityAnalysis/CLDQualityAnalysis.swift",
    "content": "//\n//  CLDQualityAnalysis.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDQualityAnalysis: CLDBaseResult {\n    \n    open var blockiness: NSNumber? {\n        guard let blockiness = getParam(.blockiness) as? NSNumber else { return nil }\n        \n        return blockiness\n    }\n    open var chromaSubsampling: NSNumber? {\n        guard let chromaSubsampling = getParam(.chromaSubsampling) as? NSNumber else { return nil }\n        \n        return chromaSubsampling\n    }\n    open var resolution: NSNumber? {\n        guard let resolution = getParam(.resolution) as? NSNumber else { return nil }\n        \n        return resolution\n    }\n    open var noise: NSNumber? {\n        guard let noise = getParam(.noise) as? NSNumber else { return nil }\n        \n        return noise\n    }\n    open var colorScore: NSNumber? {\n        guard let colorScore = getParam(.colorScore) as? NSNumber else { return nil }\n        \n        return colorScore\n    }\n    open var jpegChroma: NSNumber? {\n        guard let jpegChroma = getParam(.jpegChroma) as? NSNumber else { return nil }\n        \n        return jpegChroma\n    }\n    open var dct: NSNumber? {\n        guard let dct = getParam(.dct) as? NSNumber else { return nil }\n        \n        return dct\n    }\n    open var jpegQuality: NSNumber? {\n        guard let jpegQuality = getParam(.jpegQuality) as? NSNumber else { return nil }\n        \n        return jpegQuality\n    }\n    open var focus: NSNumber? {\n        guard let focus = getParam(.focus) as? NSNumber else { return nil }\n        \n        return focus\n    }\n    open var saturation: NSNumber? {\n        guard let saturation = getParam(.saturation) as? NSNumber else { return nil }\n        \n        return saturation\n    }\n    open var contrast: NSNumber? {\n        guard let contrast = getParam(.contrast) as? NSNumber else { return nil }\n        \n        return contrast\n    }\n    open var exposure: NSNumber? {\n        guard let exposure = getParam(.exposure) as? NSNumber else { return nil }\n        \n        return exposure\n    }\n    open var lighting: NSNumber? {\n        guard let lighting = getParam(.lighting) as? NSNumber else { return nil }\n        \n        return lighting\n    }\n    open var pixelScore: NSNumber? {\n        guard let pixelScore = getParam(.pixelScore) as? NSNumber else { return nil }\n        \n        return pixelScore\n    }\n    \n    // MARK: - Private Helpers\n    fileprivate func getParam(_ param: CLDQualityAnalysisKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDQualityAnalysisKey: CustomStringConvertible {\n        case blockiness, chromaSubsampling, resolution, noise, colorScore, jpegChroma, dct, jpegQuality, focus, saturation, contrast, exposure, lighting, pixelScore\n        \n        var description: String {\n            switch self {\n            case .blockiness: return \"blockiness\"\n            case .chromaSubsampling: return \"chroma_subsampling\"\n            case .resolution: return \"resolution\"\n            case .noise: return \"noise\"\n            case .colorScore: return \"color_score\"\n            case .jpegChroma: return \"jpeg_chroma\"\n            case .dct: return \"dct\"\n            case .jpegQuality: return \"jpeg_quality\"\n            case .focus: return \"focus\"\n            case .saturation: return \"saturation\"\n            case .contrast: return \"contrast\"\n            case .exposure: return \"exposure\"\n            case .lighting: return \"lighting\"\n            case .pixelScore: return \"pixel_score\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CLDRekognitionFace.swift",
    "content": "//\n//  CLDRekognitionFace.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDRekognitionFace: CLDBaseResult {\n    \n    open var status: String? {\n        return getParam(.status) as? String\n    }\n    \n    open var faces: [CLDFace]? {\n        guard let facesArr = getParam(.faces) as? [[String : AnyObject]] else {\n            return nil\n        }\n        var faces: [CLDFace] = []\n        for face in facesArr {\n            faces.append(CLDFace(json: face))\n        }\n        return faces\n    }\n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: CLDRekognitionFaceKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDRekognitionFaceKey: CustomStringConvertible {\n        case status, facesData\n        \n        var description: String {\n            switch self {\n            case .status:           return \"status\"\n            case .facesData:        return \"data\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Helpers/Results/Helpers/CommonResultKeys.swift",
    "content": "//\n//  CommonResultKeys.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal enum CommonResultKeys: CustomStringConvertible {\n    case publicId, format, version, resourceType, urlType, createdAt, length, width, height, x, y, url, secureUrl, exif, metadata, faces, colors, tags, moderation, context, phash, info, accessControl, eager, qualityAnalysis, coordinates, accessibilityAnalysis, originalFilename, assetFolder, displayName, playbackUrl, metadata_object\n\n    var description: String {\n        switch self {\n        case .publicId:              return \"public_id\"\n        case .format:                return \"format\"\n        case .version:               return \"version\"\n        case .resourceType:          return \"resource_type\"\n        case .urlType:               return \"type\"\n        case .createdAt:             return \"created_at\"\n        case .length:                return \"bytes\"\n        case .width:                 return \"width\"\n        case .height:                return \"height\"\n        case .x:                     return \"x\"\n        case .y:                     return \"y\"\n        case .url:                   return \"url\"\n        case .secureUrl:             return \"secure_url\"\n        case .exif:                  return \"exif\"\n        case .metadata:              return \"image_metadata\"\n        case .faces:                 return \"faces\"\n        case .colors:                return \"colors\"\n        case .tags:                  return \"tags\"\n        case .moderation:            return \"moderation\"\n        case .context:               return \"context\"\n        case .phash:                 return \"phash\"\n        case .info:                  return \"info\"\n        case .eager:                 return \"eager\"\n        case .accessControl:         return \"access_control\"\n        case .qualityAnalysis:       return \"quality_analysis\"\n        case .accessibilityAnalysis: return \"accessibility_analysis\"\n        case .coordinates:           return \"coordinates\"\n        case .originalFilename:      return \"original_filename\"\n        case .assetFolder:           return \"asset_folder\"\n        case .displayName:           return \"display_name\"\n        case .playbackUrl:           return \"playback_url\"\n        case .metadata_object:       return \"metadata\"\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/CLDManagementApi.swift",
    "content": "//\n//  CLDManagementApi.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The CLDManagementApi class is used to perform the available methods for managing your cloud assets.\n*/\n@objcMembers open class CLDManagementApi: CLDBaseNetworkObject {\n    \n    // MARK: - Init\n    \n    fileprivate override init() {\n        super.init()\n    }\n    \n    override internal init(networkCoordinator:CLDNetworkCoordinator) {\n        super.init(networkCoordinator: networkCoordinator)\n    }\n    \n    \n    // MARK: - Features\n    \n    /**\n    Rename an asset on your cloud.\n    \n    - parameter publicId:               The current identifier of the uploaded asset.\n    - parameter to:                     The new identifier to assign to the uploaded asset.\n    - parameter overwrite:              A boolean parameter indicating whether or not to overwrite an existing image with the target Public ID. Default: false.\n    - parameter invalidate:             A boolean parameter indicating whether to invalidate CDN cached copies of the image (and all its transformed versions). Default: false.\n    - parameter params:                 An object holding the available parameters for the request.\n    - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n    \n    - returns:              An instance of `CLDRenameRequest`,\n                            allowing the options to add response closure to be called once the request has finished,\n                            as well as performing actions on the request, such as cancelling, suspending or resuming it.\n    */\n    @discardableResult\n    open func rename(_ publicId: String, to: String, overwrite: Bool? = nil, invalidate: Bool? = nil, params: CLDRenameRequestParams? = nil, completionHandler: ((_ result: CLDRenameResult?, _ error: Error?) -> ())? = nil) -> CLDRenameRequest {\n        let renameParams = CLDRenameRequestParams(fromPublicId: publicId, toPublicId: to, overwrite: overwrite, invalidate: invalidate)\n        renameParams.merge(params)\n        let request = networkCoordinator.callAction(.Rename, params:renameParams)\n        let renameRequest = CLDRenameRequest(networkRequest: request)\n        renameRequest.response(completionHandler)\n        return renameRequest\n    }\n    \n    /**\n     Immediately and permanently delete assets from your Cloudinary account\n     \n     - parameter publicId:              The identifier of the asset to remove.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDDeleteRequest`,\n                            allowing the options to add response closure to be called once the request has finished,\n                            as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func destroy(_ publicId: String, params: CLDDestroyRequestParams? = nil, completionHandler: ((_ result: CLDDeleteResult?, _ error: Error?) -> ())? = nil) -> CLDDeleteRequest {\n        let destroyParams = CLDDestroyRequestParams(publicId: publicId)\n        destroyParams.merge(params)\n        let request = networkCoordinator.callAction(.Destroy, params: destroyParams)\n        let destroyRequest = CLDDeleteRequest(networkRequest: request)\n        destroyRequest.response(completionHandler)\n        return destroyRequest\n    }\n    \n    /**\n     Add a tag to one or more assets in your cloud.\n     Tags are used to categorize and organize your images, and can also be used to apply group actions to images,\n     for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs.\n     Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags).\n     \n     - parameter tag:                   The tag to assign.\n     - parameter publicIds:             An array of Public IDs of images uploaded to Cloudinary.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDTagRequest`,\n                            allowing the options to add response closure to be called once the request has finished,\n                            as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func addTag(_ tag: String, publicIds: [String], params: CLDTagsRequestParams? = nil, completionHandler: ((_ result: CLDTagResult?, _ error: Error?) -> ())? = nil) -> CLDTagRequest {\n        let addTagParams = CLDTagsRequestParams(tags: [tag], publicIds: publicIds)\n        addTagParams.merge(params)\n        \n        let request = networkCoordinator.callAction(.Tags, params: addTagParams.setCommand(.add))\n        let tagRequest = CLDTagRequest(networkRequest: request)\n        tagRequest.response(completionHandler)\n        return tagRequest\n    }\n    \n    /**\n     Add the tags to one or more assets in your cloud.\n     Tags are used to categorize and organize your images, and can also be used to apply group actions to images,\n     for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs.\n     Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags).\n     \n     - parameter tag:                  An array of tags to assign\n     - parameter publicIds:             An array of Public IDs of images uploaded to Cloudinary.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDTagRequest`,\n                            allowing the options to add response closure to be called once the request has finished,\n                            as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    @objc(addTags:publicIds:params:completionHandler:)\n    open func addTag(_ tag: [String], publicIds: [String], params: CLDTagsRequestParams? = nil, completionHandler: ((_ result: CLDTagResult?, _ error: Error?) -> ())? = nil) -> CLDTagRequest {\n        let addTagParams = CLDTagsRequestParams(tags: tag, publicIds: publicIds)\n        addTagParams.merge(params)\n        \n        let request = networkCoordinator.callAction(.Tags, params: addTagParams.setCommand(.add))\n        let tagRequest = CLDTagRequest(networkRequest: request)\n        tagRequest.response(completionHandler)\n        return tagRequest\n    }\n    \n    /**\n     Remove a tag to one or more assets in your cloud.\n     Tags are used to categorize and organize your images, and can also be used to apply group actions to images,\n     for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs.\n     Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags).\n     \n     - parameter tag:                   The tag to remove.\n     - parameter publicIds:             An array of Public IDs of images uploaded to Cloudinary.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDTagRequest`,\n     allowing the options to add response closure to be called once the request has finished,\n     as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func removeTag(_ tag: String, publicIds: [String], params: CLDTagsRequestParams? = nil, completionHandler: ((_ result: CLDTagResult?, _ error: Error?) -> ())? = nil) -> CLDTagRequest {\n        let removeTagParams = CLDTagsRequestParams(tags: [tag], publicIds: publicIds)\n        removeTagParams.merge(params)\n        let request = networkCoordinator.callAction(.Tags, params: removeTagParams.setCommand(.remove))\n        let tagRequest = CLDTagRequest(networkRequest: request)\n        tagRequest.response(completionHandler)\n        return tagRequest\n    }\n    \n    /**\n     Remove tags to one or more assets in your cloud.\n     Tags are used to categorize and organize your images, and can also be used to apply group actions to images,\n     for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs.\n     Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags).\n     \n     - parameter tag:                  An array of tags to remove\n     - parameter publicIds:             An array of Public IDs of images uploaded to Cloudinary.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDTagRequest`,\n     allowing the options to add response closure to be called once the request has finished,\n     as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    @objc(removeTags:publicIds:params:completionHandler:)\n    open func removeTag(_ tag: [String], publicIds: [String], params: CLDTagsRequestParams? = nil, completionHandler: ((_ result: CLDTagResult?, _ error: Error?) -> ())? = nil) -> CLDTagRequest {\n        let removeTagParams = CLDTagsRequestParams(tags: tag, publicIds: publicIds)\n        removeTagParams.merge(params)\n        let request = networkCoordinator.callAction(.Tags, params: removeTagParams.setCommand(.remove))\n        let tagRequest = CLDTagRequest(networkRequest: request)\n        tagRequest.response(completionHandler)\n        return tagRequest\n    }\n    \n    /**\n     Replaces a tag to one or more assets in your cloud.\n     Tags are used to categorize and organize your images, and can also be used to apply group actions to images,\n     for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs.\n     Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags).\n     \n     - parameter tag:                   The tag to replace.\n     - parameter publicIds:             An array of Public IDs of images uploaded to Cloudinary.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDTagRequest`,\n     allowing the options to add response closure to be called once the request has finished,\n     as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func replaceTag(_ tag: String, publicIds: [String], params: CLDTagsRequestParams? = nil, completionHandler: ((_ result: CLDTagResult?, _ error: Error?) -> ())? = nil) -> CLDTagRequest {\n        let replaceTagParams = CLDTagsRequestParams(tags: [tag], publicIds: publicIds)\n        replaceTagParams.merge(params)\n        let request = networkCoordinator.callAction(.Tags, params: replaceTagParams.setCommand(.replace))\n        let tagRequest = CLDTagRequest(networkRequest: request)\n        tagRequest.response(completionHandler)\n        return tagRequest\n    }\n    \n    /**\n     Replaces tags to one or more assets in your cloud.\n     Tags are used to categorize and organize your images, and can also be used to apply group actions to images,\n     for example to delete images, create sprites, ZIP files, JSON lists, or animated GIFs.\n     Each image can be assigned one or more tags, which is a short name that you can dynamically use (no need to predefine tags).\n     \n     - parameter tag:                   The array of tags to replace.\n     - parameter publicIds:             An array of Public IDs of images uploaded to Cloudinary.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDTagRequest`,\n     allowing the options to add response closure to be called once the request has finished,\n     as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    @objc(replaceTags:publicIds:params:completionHandler:)\n    open func replaceTag(_ tag: [String], publicIds: [String], params: CLDTagsRequestParams? = nil, completionHandler: ((_ result: CLDTagResult?, _ error: Error?) -> ())? = nil) -> CLDTagRequest {\n        let replaceTagParams = CLDTagsRequestParams(tags: tag, publicIds: publicIds)\n        replaceTagParams.merge(params)\n        let request = networkCoordinator.callAction(.Tags, params: replaceTagParams.setCommand(.replace))\n        let tagRequest = CLDTagRequest(networkRequest: request)\n        tagRequest.response(completionHandler)\n        return tagRequest\n    }\n    \n    /**\n     The explicit method is used to apply actions to already uploaded images, i.e., to update images that have already been uploaded.\n     The most common usage of this method is to generate transformations for images that have already been uploaded,\n     either so that they do not need to be generated on the fly when first accessed by users,\n     or because Strict Transformations are enabled for your account and you cannot create transformed images on the fly (for more information, see [Access control to images](http://cloudinary.com/documentation/upload_images#control_access_to_images)).\n     \n     - parameter publicId:              The identifier of the uploaded asset.\n     - parameter type:                  The specific type of the resource.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDExplicitRequest`,\n                            allowing the options to add response closure to be called once the request has finished,\n                            as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    @objc(explicitPublicId:stringType:params:completionHandler:)\n    open func explicit(_ publicId: String, type: String, params: CLDExplicitRequestParams? = nil, completionHandler: ((_ result: CLDExplicitResult?, _ error: Error?) -> ())? = nil) -> CLDExplicitRequest {\n        let explicitParams = CLDExplicitRequestParams(publicId: publicId, type: type)\n        explicitParams.merge(params)\n        let request = networkCoordinator.callAction(.Explicit, params: explicitParams)\n        let explicitRequest = CLDExplicitRequest(networkRequest: request)\n        explicitRequest.response(completionHandler)\n        return explicitRequest\n    }\n    \n    /**\n     The explicit method is used to apply actions to already uploaded images, i.e., to update images that have already been uploaded.\n     The most common usage of this method is to generate transformations for images that have already been uploaded,\n     either so that they do not need to be generated on the fly when first accessed by users,\n     or because Strict Transformations are enabled for your account and you cannot create transformed images on the fly (for more information, see [Access control to images](http://cloudinary.com/documentation/upload_images#control_access_to_images)).\n     \n     - parameter publicId:              The identifier of the uploaded asset.\n     - parameter type:                  The specific type of the resource.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDExplicitRequest`,\n     allowing the options to add response closure to be called once the request has finished,\n     as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func explicit(_ publicId: String, type: CLDType, params: CLDExplicitRequestParams? = nil, completionHandler: ((_ result: CLDExplicitResult?, _ error: Error?) -> ())? = nil) -> CLDExplicitRequest {\n        return explicit(publicId, type: String(describing: type), params: params, completionHandler: completionHandler)\n    }\n    \n    /**\n     The explode method creates derived images for all the individual pages in a PDF file.\n     Each derived image created is stored with the same Public ID as the PDF file,\n     and can be accessed using the page parameter for delivering an image of a specific PDF page.\n     This method is useful for pregenerating all the pages of the PDF as individual images so that they do not need to be generated on the fly when first accessed by your users.\n     \n     - parameter publicId:              The identifier of the uploaded asset.\n     - parameter transformation:        A transformation to run on all the pages before storing them as derived images. This parameter is given as an array (using the SDKs) or comma-separated list          (for direct API calls) of transformations, and separated with a slash for chained transformations.\n     At minimum, you must pass the page transformation with the value all. If you supply additional transformations, you must deliver the image using the same relative order of the page and the other transformations. If you use a different order when you deliver, then it is considered a different transformation, and will be generated on-the-fly as a new derived image.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDExplodeRequest`,\n                            allowing the options to add response closure to be called once the request has finished,\n                            as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func explode(_ publicId: String, transformation: CLDTransformation, params: CLDExplodeRequestParams? = nil, completionHandler: ((_ result: CLDExplodeResult?, _ error: Error?) -> ())? = nil) -> CLDExplodeRequest {\n        let explodeParams = CLDExplodeRequestParams(publicId: publicId, transformation: transformation)\n        explodeParams.merge(params)\n        let request = networkCoordinator.callAction(.Explode, params: explodeParams)\n        let explodeRequest = CLDExplodeRequest(networkRequest: request)\n        explodeRequest.response(completionHandler)\n        return explodeRequest\n    }\n    \n    /**\n     Generate sprites by merging multiple images into a single large image for reducing network overhead and bypassing download limitations.\n     This method creates a sprite from all images that have been assigned a specified tag.\n     \n     - parameter tag:                   The sprite is created from all images with this tag.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDSpriteRequest`,\n                            allowing the options to add response closure to be called once the request has finished,\n                            as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func generateSprite(_ tag: String, params: CLDSpriteRequestParams? = nil, completionHandler: ((_ result: CLDSpriteResult?, _ error: Error?) -> ())? = nil) -> CLDSpriteRequest {\n        let generateSpriteParams = CLDSpriteRequestParams(tag: tag)\n        generateSpriteParams.merge(params)\n        let request = networkCoordinator.callAction(.GenerateSprite, params: generateSpriteParams)\n        let spriteRequest = CLDSpriteRequest(networkRequest: request)\n        spriteRequest.response(completionHandler)\n        return spriteRequest\n    }\n    \n    /**\n    Create a single animated GIF file from all images that have been assigned a specified tag,\n     where each image is included as a single frame of the resulting animating GIF (sorted alphabetically by their Public ID).\n     For a detailed explanation on generating animated GIFs, see the [documentation on creating animated GIFs.](http://cloudinary.com/documentation/image_transformations#creating_animated_gifs)\n     \n     - parameter tag:                   The sprite is created from all images with this tag.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDMultiRequest`,\n                            allowing the options to add response closure to be called once the request has finished,\n                            as well as performing actions on the request, such as cancelling, suspending or resuming it.\n    */\n    @discardableResult\n    open func multi(_ tag: String, params: CLDMultiRequestParams? = nil, completionHandler: ((_ result: CLDMultiResult?, _ error: Error?) -> ())? = nil) -> CLDMultiRequest {\n        let multiParams = CLDMultiRequestParams(tag: tag)\n        multiParams.merge(params)\n        let request = networkCoordinator.callAction(.Multi, params: multiParams)\n        let multiRequest = CLDMultiRequest(networkRequest: request)\n        multiRequest.response(completionHandler)\n        return multiRequest\n    }\n    \n    /**\n     Dynamically generate an image from a given textual string.\n     You can then use this textual image as any other image,\n     for example, as an overlay for other images. Various font,\n     color and style parameters can be specified to customize the look & feel of the text before converting it to an image.\n     \n     - parameter text:                  The text string to generate an image for.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDTextRequest`,\n                            allowing the options to add response closure to be called once the request has finished,\n                            as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func text(_ text: String, params: CLDTextRequestParams? = nil, completionHandler: ((_ result: CLDTextResult?, _ error: Error?) -> ())? = nil) -> CLDTextRequest {\n        let textParams = CLDTextRequestParams(text: text)\n        textParams.merge(params)\n        let request = networkCoordinator.callAction(.GenerateText, params: textParams)\n        let textRequest = CLDTextRequest(networkRequest: request)\n        textRequest.response(completionHandler)\n        return textRequest\n    }\n    \n    /**\n     The Cloudinary library supports using a delete token to delete images on the client-side for a limited time of 10 minutes after being uploaded.\n     After 10 minutes has passed, the image cannot be deleted from the client side, only via the Destroy method.\n     In order to also receive a deletion token in the upload response, add the return_delete_token parameter to the upload method and set it to true.\n     \n     - parameter token:                 The delete token received in the upload response, after uploading the asset using `return_delete_token` set to true.\n     - parameter params:                An object holding the available parameters for the request.\n     - parameter completionHandler:     The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:             An instance of `CLDDeleteRequest`,\n                            allowing the options to add response closure to be called once the request has finished,\n                            as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func deleteByToken(_ token: String, params: CLDDeleteByTokenRequestParams? = nil, completionHandler: ((_ result: CLDDeleteResult?, _ error: Error?) -> ())? = nil) -> CLDDeleteRequest {\n        let deleteByTokenParams = CLDDeleteByTokenRequestParams(token: token)\n        deleteByTokenParams.merge(params)\n        let request = networkCoordinator.callAction(.DeleteByToken, params: deleteByTokenParams)\n        let deleteByTokenRequest = CLDDeleteRequest(networkRequest: request)\n        deleteByTokenRequest.response(completionHandler)\n        return deleteByTokenRequest\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Requests/CLDDeleteRequest.swift",
    "content": "//\n//  CLDDeleteRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The `CLDExplodeRequest` object is returned when creating an explode request.\n It allows the options to add a response closure to be called once the request has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n@objcMembers open class CLDDeleteRequest: CLDRequest {\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDDeleteRequest.\n     */\n    @discardableResult\n    open func response(_ completionHandler: ((_ result: CLDDeleteResult?, _ error: NSError?) -> ())?) -> CLDDeleteRequest {\n        responseRaw { (response, error) in\n            if let res = response as? [String : AnyObject] {\n                completionHandler?(CLDDeleteResult(json: res), nil)\n            }\n            else if let err = error {\n                completionHandler?(nil, err)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n        }\n        \n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Requests/CLDExplicitRequest.swift",
    "content": "//\n//  CLDExplicitRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The `CLDExplodeRequest` object is returned when creating an explode request.\n It allows the options to add a response closure to be called once the request has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n@objcMembers open class CLDExplicitRequest: CLDRequest {\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDExplicitRequest.\n     */\n    @discardableResult\n    open func response(_ completionHandler: ((_ result: CLDExplicitResult?, _ error: NSError?) -> ())?) -> CLDExplicitRequest {\n        responseRaw { (response, error) in\n            if let res = response as? [String : AnyObject] {\n                completionHandler?(CLDExplicitResult(json: res), nil)\n            }\n            else if let err = error {\n                completionHandler?(nil, err)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n        }\n        \n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Requests/CLDExplodeRequest.swift",
    "content": "//\n//  CLDExplodeRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The `CLDExplodeRequest` object is returned when creating an explode request.\n It allows the options to add a response closure to be called once the request has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n@objcMembers open class CLDExplodeRequest: CLDRequest {\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDExplodeRequest.\n     */\n    @discardableResult\n    open func response(_ completionHandler: ((_ result: CLDExplodeResult?, _ error: NSError?) -> ())?) -> CLDExplodeRequest {\n        responseRaw { (response, error) in\n            if let res = response as? [String : AnyObject] {\n                completionHandler?(CLDExplodeResult(json: res), nil)\n            }\n            else if let err = error {\n                completionHandler?(nil, err)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n        }\n        \n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Requests/CLDMultiRequest.swift",
    "content": "//\n//  CLDMultiRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The `CLDMultiRequest` object is returned when creating a multi request.\n It allows the options to add a response closure to be called once the request has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n@objcMembers open class CLDMultiRequest: CLDRequest {\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDMultiRequest.\n     */\n    @discardableResult\n    open func response(_ completionHandler: ((_ result: CLDMultiResult?, _ error: NSError?) -> ())?) -> CLDMultiRequest {\n        responseRaw { (response, error) in\n            if let res = response as? [String : AnyObject] {\n                completionHandler?(CLDMultiResult(json: res), nil)\n            }\n            else if let err = error {\n                completionHandler?(nil, err)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n        }\n        \n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Requests/CLDRenameRequest.swift",
    "content": "//\n//  CLDRenameRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The `CLDRenameRequest` object is returned when creating a rename request.\n It allows the options to add a response closure to be called once the request has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n@objcMembers open class CLDRenameRequest: CLDRequest {\n\n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDRenameRequest.\n     */\n    @discardableResult\n    open func response(_ completionHandler: ((_ result: CLDRenameResult?, _ error: NSError?) -> ())?) -> CLDRenameRequest {\n        responseRaw { (response, error) in\n            if let res = response as? [String : AnyObject] {\n                completionHandler?(CLDRenameResult(json: res), nil)\n            }\n            else if let err = error {\n                completionHandler?(nil, err)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n        }\n        \n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Requests/CLDSpriteRequest.swift",
    "content": "//\n//  CLDSpriteRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The `CLDSpriteRequest` object is returned when creating a sprite request.\n It allows the options to add a response closure to be called once the request has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n@objcMembers open class CLDSpriteRequest: CLDRequest {\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDSpriteRequest.\n     */\n    @discardableResult\n    open func response(_ completionHandler: ((_ result: CLDSpriteResult?, _ error: NSError?) -> ())?) -> CLDSpriteRequest {\n        responseRaw { (response, error) in\n            if let res = response as? [String : AnyObject] {\n                completionHandler?(CLDSpriteResult(json: res), nil)\n            }\n            else if let err = error {\n                completionHandler?(nil, err)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n        }\n        \n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Requests/CLDTagRequest.swift",
    "content": "//\n//  CLDTagRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The `CLDTagRequest` object is returned when creating a tag request.\n It allows the options to add a response closure to be called once the request has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n@objcMembers open class CLDTagRequest: CLDRequest {\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDTagRequest.\n     */\n    @discardableResult\n    open func response(_ completionHandler: ((_ result: CLDTagResult?, _ error: NSError?) -> ())?) -> CLDTagRequest {\n        responseRaw { (response, error) in\n            if let res = response as? [String : AnyObject] {\n                completionHandler?(CLDTagResult(json: res), nil)\n            }\n            else if let err = error {\n                completionHandler?(nil, err)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n        }\n        \n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Requests/CLDTextRequest.swift",
    "content": "//\n//  CLDTextRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The `CLDTagRequest` object is returned when creating a tag request.\n It allows the options to add a response closure to be called once the request has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n@objcMembers open class CLDTextRequest: CLDRequest {\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDTextRequest.\n     */\n    @discardableResult\n    open func response(_ completionHandler: ((_ result: CLDTextResult?, _ error: NSError?) -> ())?) -> CLDTextRequest {\n        responseRaw { (response, error) in\n            if let res = response as? [String : AnyObject] {\n                completionHandler?(CLDTextResult(json: res), nil)\n            }\n            else if let err = error {\n                completionHandler?(nil, err)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n        }\n        \n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/RequestsParams/CLDDeleteByTokenRequestParams.swift",
    "content": "//\n//  CLDDeleteByTokenRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n This class represents the different parameters that can be passed when performing a `delete by token` request.\n */\nopen class CLDDeleteByTokenRequestParams: CLDRequestParams {\n\n    \n    // MARK: Init\n    \n    fileprivate override init() {\n        super.init()\n    }\n    \n    /**\n    Initializes a CLDDeleteByTokenRequestParams instance.\n    \n    - parameter token:      The delete token received in the upload response, after uploading the asset using `return_delete_token` set to true.\n    \n    - returns:              A new instance of CLDDeleteByTokenRequestParams.\n    */\n    internal init(token: String) {\n        super.init()\n        setParam(DeleteByTokenParams.Token.rawValue, value: token)\n    }\n    \n    /**\n     Initializes a CLDDeleteByTokenRequestParams instance.\n     \n     - parameter params:    A dictionary of the request parameters.\n     \n     - returns:             A new instance of CLDDeleteByTokenRequestParams.\n     */\n    public init(params: [String : Any]) {\n        super.init()\n        self.params = params\n    }\n    \n    // MARK: Params\n    \n    fileprivate enum DeleteByTokenParams: String {\n        case Token =                \"token\"\n    }\n    \n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/RequestsParams/CLDDestroyRequestParams.swift",
    "content": "//\n//  CLDDestroyRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n This class represents the different parameters that can be passed when performing a destroy request.\n */\n@objcMembers open class CLDDestroyRequestParams: CLDRequestParams {\n    \n    //MARK: Init\n    \n    public override init() {\n        super.init()\n    }\n    \n    /**\n    Initializes a CLDDestroyRequestParams instance.\n    \n    - parameter publicId:           The identifier of the asset to remove.\n    \n    - returns:                       A new instance of CLDDestroyRequestParams.\n    */\n    internal init(publicId: String) {\n        super.init()\n        setParam(DestroyParams.PublicId.rawValue, value: publicId)\n    }\n    \n    /**\n     Initializes a CLDDestroyRequestParams instance.\n     \n     - parameter params:    A dictionary of the request parameters.\n     \n     - returns:             A new instance of CLDDestroyRequestParams.\n     */\n    public init(params: [String : AnyObject]) {\n        super.init()\n        self.params = params\n    }\n    \n    //MARK: Set Params\n    \n    /**\n    Set the specific file type of the resource using one of the available options from CLDType.\n    \n    - parameter type:       The file type to set.\n    \n    - returns:              The same instance of CLDDestroyRequestParams.\n    */\n    @discardableResult\n    @objc(setTypeWithType:)\n    open func setType(_ type: CLDType) -> Self {\n        return setType(String(describing: type))\n    }\n    \n    /**\n     Set the specific file type of the resource.\n     \n     - parameter type:       The specific file type of the resource.\n     \n     - returns:              The same instance of CLDExplodeRequestParams.\n     */\n    @discardableResult\n    open func setType(_ type: String) -> Self {\n        super.setParam(DestroyParams.CloudType.rawValue, value: type)\n        return self\n    }\n    \n    /**\n     Set boolean parameter indicating whether or not the asset should be invalidated through the CDN. default is false.\n     \n     - parameter invalidate:    The boolean parameter.\n     \n    - returns:              The same instance of CLDDestroyRequestParams.\n    */\n    @discardableResult\n    open func setInvalidate(_ invalidate: Bool) -> Self {\n        super.setParam(DestroyParams.Invalidate.rawValue, value: invalidate)\n        return self\n    }\n    \n    fileprivate enum DestroyParams: String {\n        case PublicId =             \"public_id\"\n        case CloudType =            \"type\"\n        case Invalidate =           \"invalidate\"\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/RequestsParams/CLDExplicitRequestParams.swift",
    "content": "//\n//  CLDExplicitRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n This class represents the different parameters that can be passed when performing an `explicit` request.\n */\n@objcMembers open class CLDExplicitRequestParams: CLDUploadRequestParams {\n\n    \n    //MARK: Init\n    \n    public override init() {\n        super.init()\n    }\n    \n    /**\n    Initializes a CLDExplicitRequestParams instance.\n    \n    - parameter publicId:           The identifier of the uploaded asset.\n    - parameter type:               The specific file type of the resource.\n    \n    - returns:                       A new instance of CLDExplicitRequestParams.\n    */\n    internal convenience init(publicId: String, type: CLDType) {\n        self.init(publicId: publicId, type: String(describing: type))\n    }\n    \n    /**\n     Initializes a CLDExplicitRequestParams instance.\n     \n     - parameter publicId:           The identifier of the uploaded asset.\n     - parameter type:               The specific file type of the resource.\n     \n     - returns:                       A new instance of CLDExplicitRequestParams.\n     */\n    @objc(initWithPublicId:andType:)\n    internal init(publicId: String, type: String) {\n        super.init()\n        setPublicId(publicId)\n        setType(type)\n    }\n    \n    /**\n     Initializes a CLDExplicitRequestParams instance.\n     \n     - parameter params:    A dictionary of the request parameters.\n     \n     - returns:             A new instance of CLDExplicitRequestParams.\n     */\n    public override init(params: [String : AnyObject]) {\n        super.init(params: params)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/RequestsParams/CLDExplodeRequestParams.swift",
    "content": "//\n//  CLDExplodeRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n This class represents the different parameters that can be passed when performing an `explode` request.\n */\n@objcMembers open class CLDExplodeRequestParams: CLDRequestParams {\n\n    \n    // MARK: Init\n    \n    public override init() {\n        super.init()\n    }\n    \n    /**\n    Initializes a CLDExplodeRequestParams instance.\n    \n    - parameter publicId:           The identifier of the uploaded asset.\n    - parameter transformation:     A transformation to run on all the pages before storing them as derived images. This parameter is given as an array (using the SDKs) or comma-separated list (for direct API calls) of transformations, and separated with a slash for chained transformations.\n        At minimum, you must pass the page transformation with the value all. If you supply additional transformations, you must deliver the image using the same relative order of the page and the other transformations. If you use a different order when you deliver, then it is considered a different transformation, and will be generated on-the-fly as a new derived image.\n    \n    - returns:                       A new instance of CLDExplodeRequestParams.\n    */\n    internal init(publicId: String, transformation: CLDTransformation) {\n        super.init()\n        setParam(ExplodeParams.PublicId.rawValue, value: publicId)\n        setParam(ExplodeParams.Transformation.rawValue, value: transformation.asString())\n    }\n    \n    /**\n     Initializes a CLDExplodeRequestParams instance.\n     \n     - parameter params:    A dictionary of the request parameters.\n     \n     - returns:             A new instance of CLDExplodeRequestParams.\n     */\n    public init(params: [String : AnyObject]) {\n        super.init()\n        self.params = params\n    }\n    \n    // MARK: Set Params\n    \n    /**\n    Set the specific file type of the resource.\n    \n    - parameter type:       The specific file type of the resource.\n    \n    - returns:              The same instance of CLDExplodeRequestParams.\n    */\n    @discardableResult\n    @objc(setTypeWithType:)\n    open func setType(_ type: CLDType) -> Self {\n        return setType(String(describing: type))\n    }\n    \n    /**\n     Set the specific file type of the resource.\n     \n     - parameter type:       The specific file type of the resource.\n     \n     - returns:              The same instance of CLDExplodeRequestParams.\n     */\n    @discardableResult\n    open func setType(_ type: String) -> Self {\n        setParam(ExplodeParams.CloudType.rawValue, value: type)\n        return self\n    }\n    \n    /**\n     Set a format to convert the images before storing them in your Cloudinary account. default is jpg.\n     \n     - parameter format:        The format to convert to.\n     \n     - returns:                 The same instance of CLDExplodeRequestParams.\n     */\n    @discardableResult\n    open func setFormat(_ format: String) -> Self {\n        setParam(ExplodeParams.Format.rawValue, value: format)\n        return self\n    }\n    \n    /**\n     Set a boolean parameter indicating whether to perform the image generation in the background (asynchronously). default is false.\n     \n     - parameter async:         The boolean parameter.\n     \n     - returns:                 The same instance of CLDExplodeRequestParams.\n     */\n    @discardableResult\n    open func setAsync(_ async: Bool) -> Self {\n        setParam(ExplodeParams.Async.rawValue, value: async)\n        return self\n    }\n    \n    /**\n     Set an HTTP or HTTPS URL to notify your application (a webhook) when the process has completed.\n     \n     - parameter notificationUrl:       The URL.\n     \n     - returns:                         The same instance of CLDExplodeRequestParams.\n     */\n    @discardableResult\n    open func setNotificationUrl(_ notificationUrl: String) -> Self {\n        setParam(ExplodeParams.NotificationUrl.rawValue, value: notificationUrl)\n        return self\n    }\n    \n    \n    \n    fileprivate enum ExplodeParams: String {\n        case PublicId =             \"public_id\"\n        case CloudType =            \"type\"\n        case Transformation =       \"transformation\"\n        case Format =               \"format\"\n        case Async =                \"async\"\n        case NotificationUrl =      \"notification_url\"\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/RequestsParams/CLDMultiRequestParams.swift",
    "content": "//\n//  CLDMultiRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n This class represents the different parameters that can be passed when performing a request to generate a multi-image.\n */\nopen class CLDMultiRequestParams: CLDRequestParams {\n\n    // MARK: Init\n    \n    public override init() {\n        super.init()\n    }\n    \n    /**\n    Initializes a CLDMultiRequestParams instance.\n    \n    - parameter tag:        The sprite is created from all images with this tag.\n    \n    - returns:              A new instance of CLDMultiRequestParams.\n    */\n    internal init(tag: String) {\n        super.init()\n        setParam(MultiParams.Tag.rawValue, value: tag)\n    }\n    \n    /**\n     Initializes a CLDMultiRequestParams instance.\n     \n     - parameter params:    A dictionary of the request parameters.\n     \n     - returns:             A new instance of CLDMultiRequestParams.\n     */\n    public init(params: [String : AnyObject]) {\n        super.init()\n        self.params = params\n    }\n    \n    // MARK: Set Params\n    \n    /**\n    Set a transformation to run on all the individual images before creating the sprite.\n    \n    - parameter transformation:     The transformation to run.\n    \n    - returns:                      A new instance of CLDMultiRequestParams.\n    */\n    @discardableResult\n    open func setTransformation(_ transformation: CLDTransformation) -> Self {\n        if let trans = transformation.asString() {        \n            super.setParam(MultiParams.Transformation.rawValue, value: trans)\n        }\n        return self\n    }\n    \n    /**\n     Set a format to convert the images before storing them in your Cloudinary account. default is jpg.\n     \n     - parameter format:        The format to convert to.\n     \n     - returns:                      A new instance of CLDMultiRequestParams.\n     */\n    @discardableResult\n    open func setFormat(_ format: String) -> Self {\n        super.setParam(MultiParams.Format.rawValue, value: format)\n        return self\n    }\n    \n    /**\n     Set a boolean parameter indicating whether to perform the image generation in the background (asynchronously). default is false.\n     \n     - parameter async:         The boolean parameter.\n     \n     - returns:                      A new instance of CLDMultiRequestParams.\n     */\n    @discardableResult\n    open func setAsync(_ async: Bool) -> Self {\n        super.setParam(MultiParams.Async.rawValue, value: async)\n        return self\n    }\n    \n    /**\n     Set an HTTP or HTTPS URL to notify your application (a webhook) when the process has completed.\n     \n     - parameter notificationUrl:       The URL.\n     \n     - returns:                      A new instance of CLDMultiRequestParams.\n     */\n    @discardableResult\n    open func setNotificationUrl(_ notificationUrl: String) -> Self {\n        super.setParam(MultiParams.NotificationUrl.rawValue, value: notificationUrl)\n        return self\n    }\n    \n    \n    \n    fileprivate enum MultiParams: String {\n        case Tag =                  \"tag\"\n        case Transformation =       \"transformation\"\n        case Format =               \"format\"\n        case Async =                \"async\"\n        case NotificationUrl =      \"notification_url\"\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/RequestsParams/CLDRenameRequestParams.swift",
    "content": "//\n//  CLDRenameRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n This class represents the different parameters that can be passed when performing a rename request.\n */\n@objcMembers open class CLDRenameRequestParams: CLDRequestParams {\n\n    \n    // MARK: Init\n    \n    public override init() {\n        super.init()\n    }\n    \n    /**\n    Initializes a CLDRenameRequestParams instance.\n    \n    - parameter fromPublicId:       The current identifier of the uploaded asset.\n    - parameter toPublicId:         The new identifier to assign to the uploaded asset.\n    - parameter overwrite:          A boolean parameter indicating whether or not to overwrite an existing image with the target Public ID. Default: false.\n    - parameter invalidate:         A boolean parameter whether to invalidate CDN cached copies of the image (and all its transformed versions). Default: false.\n    - parameter notification_url         An HTTP or HTTPS URL to notify your application (a webhook) when the process has completed. If not specified, the response is sent to the Notification URL (if defined)                                                                        in the Webhook Notifications settings of your Cloudinary Console.\n    - parameter context:            A boolean parameter indicating whether to include contextual metadata for the asset in the response. Default: false.\n    - parameter metadata:           A boolean parameter indicating whether to include structured metadata for the asset in the response. Default: false.\n    - returns:                       A new instance of CLDRenameRequestParams.\n    */\n    internal init(fromPublicId: String, toPublicId: String, overwrite: Bool? = nil, invalidate: Bool? = nil, notificationUrl: String? = nil, context: Bool? = nil, metadata: Bool? = nil) {\n        super.init()\n        setParam(RenameParams.FromPublicId.rawValue, value: fromPublicId)\n        setParam(RenameParams.ToPublicId.rawValue, value: toPublicId)        \n        setParam(RenameParams.Overwrite.rawValue, value: overwrite)\n        setParam(RenameParams.Invalidate.rawValue, value: invalidate)\n        setParam(RenameParams.NotificationUrl.rawValue, value: notificationUrl)\n        setParam(RenameParams.Context.rawValue, value: context)\n        setParam(RenameParams.Metadata.rawValue, value: metadata)\n    }\n    \n    /**\n     Initializes a CLDRenameRequestParams instance.\n     \n     - parameter params:    A dictionary of the request parameters.\n     \n     - returns:             A new instance of CLDRenameRequestParams.\n     */\n    public init(params: [String : AnyObject]) {\n        super.init()\n        self.params = params\n    }\n    \n    // MARK: - Rename Params\n    \n    fileprivate enum RenameParams: String {\n        case FromPublicId =         \"from_public_id\"\n        case ToPublicId =           \"to_public_id\"\n        case Overwrite =            \"overwrite\"\n        case Invalidate =           \"invalidate\"\n        case NotificationUrl =      \"notification_url\"\n        case Context =              \"context\"\n        case Metadata =             \"metadata\"\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/RequestsParams/CLDSpriteRequestParams.swift",
    "content": "//\n//  CLDSpriteRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n This class represents the different parameters that can be passed when performing a request to generate a sprite.\n */\n@objcMembers open class CLDSpriteRequestParams: CLDRequestParams {\n\n    \n    // MARK: Init\n    \n    public override init() {\n        super.init()\n    }\n    \n    /**\n    Initializes a CLDSpriteRequestParams instance.\n    \n    - parameter tag:        The sprite is created from all images with this tag.\n    \n    - returns:              A new instance of CLDSpriteRequestParams.\n    */\n    internal init(tag: String) {\n        super.init()\n        setParam(SpriteParams.Tag.rawValue, value: tag)\n    }\n    \n    /**\n     Initializes a CLDSpriteRequestParams instance.\n     \n     - parameter params:    A dictionary of the request parameters.\n     \n     - returns:             A new instance of CLDSpriteRequestParams.\n     */\n    public init(params: [String : AnyObject]) {\n        super.init()\n        self.params = params\n    }\n    \n    // MARK: Set Params\n    \n    /**\n    Set a transformation to run on all the individual images before creating the sprite.\n    \n    - parameter transformation:     The transformation to run.\n    \n    - returns:                      A new instance of CLDSpriteRequestParams.\n    */\n    @discardableResult\n    open func setTransformation(_ transformation: CLDTransformation) -> Self {\n        if let stringRep = transformation.asString() {\n            setParam(SpriteParams.Transformation.rawValue, value: stringRep)\n        }\n        return self\n    }\n    \n    /**\n     Set a format to convert the images before storing them in your Cloudinary account. default is jpg.\n     \n     - parameter format:        The format to convert to.\n     \n     - returns:                      A new instance of CLDSpriteRequestParams.\n     */\n    @discardableResult\n    open func setFormat(_ format: String) -> Self {\n        super.setParam(SpriteParams.Format.rawValue, value: format)\n        return self\n    }\n    \n    /**\n     Set a boolean parameter indicating whether to perform the image generation in the background (asynchronously). default is false.\n     \n     - parameter async:         The boolean parameter.\n     \n     - returns:                      A new instance of CLDSpriteRequestParams.\n     */\n    @discardableResult\n    open func setAsync(_ async: Bool) -> Self {\n        super.setParam(SpriteParams.Async.rawValue, value: async)\n        return self\n    }\n    \n    /**\n     Set an HTTP or HTTPS URL to notify your application (a webhook) when the process has completed.\n     \n     - parameter notificationUrl:       The URL.\n     \n     - returns:                      A new instance of CLDSpriteRequestParams.\n     */\n    @discardableResult\n    open func setNotificationUrl(_ notificationUrl: String) -> Self {\n        super.setParam(SpriteParams.NotificationUrl.rawValue, value: notificationUrl)\n        return self\n    }\n    \n    \n    \n    fileprivate enum SpriteParams: String {\n        case Tag =                  \"tag\"\n        case Transformation =       \"transformation\"\n        case Format =               \"format\"\n        case Async =                \"async\"\n        case NotificationUrl =      \"notification_url\"\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/RequestsParams/CLDTagsRequestParams.swift",
    "content": "//\n//  CLDTagsRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n This class represents the different parameters that can be passed when performing a tag request.\n */\n@objcMembers open class CLDTagsRequestParams: CLDRequestParams {\n    \n    //MARK: Init\n    \n    public override init() {\n        super.init()\n    }\n    \n    /**\n    Initializes a CLDTagsRequestParams instance.\n    - parameter tag:                The tag to assign, remove, or replace.\n    - parameter publicIds:          An array of Public IDs of images uploaded to Cloudinary.\n    \n    - returns:                       A new instance of CLDTagsRequestParams.\n    */\n    internal init(tags: [String], publicIds: [String]) {\n        super.init()\n        setParam(TagsParams.Tag.rawValue, value: tags.joined(separator: \",\"))\n        setParam(TagsParams.PublicIds.rawValue, value: publicIds)\n    }\n    \n    /**\n     Initializes a CLDTagsRequestParams instance.\n     \n     - parameter params:    A dictionary of the request parameters.\n     \n     - returns:             A new instance of CLDTagsRequestParams.\n     */\n    public init(params: [String : AnyObject]) {\n        super.init()\n        self.params = params\n    }\n    \n    // MARK: - Set Params\n    \n    /**\n     Sets the desired action to be done.\n     \n     - parameter command:            The action to perform on asset resources using the given tag.\n     Either add the given tag, remove the given tag, or replace the given tag,\n     which adds the given tag while removing all other tags assigned.\n     \n     - returns:                       The same instance of CLDTagsRequestParams.\n     */\n    internal func setCommand(_ command: TagsCommand) -> Self {\n        setParam(TagsParams.Command.rawValue, value: command.description)\n        return self\n    }\n    \n    // MARK: Private\n    \n    fileprivate enum TagsParams: String {\n        case PublicIds =            \"public_ids\"\n        case Tag =                  \"tag\"\n        case Command =              \"command\"\n    }\n    \n    internal enum TagsCommand: CustomStringConvertible {\n        case add, remove, replace\n        \n        var description: String {\n            switch self {\n            case .add:              return \"add\"\n            case .remove:           return \"remove\"\n            case .replace:          return \"replace\"\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/RequestsParams/CLDTextRequestParams.swift",
    "content": "//\n//  CLDTextRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n This class represents the different parameters that can be passed when performing a request to generate a text-image.\n */\nopen class CLDTextRequestParams: CLDRequestParams {\n    \n    // MARK: Init\n    \n    public override init() {\n        super.init()\n    }\n    \n    /**\n    Initializes a CLDTextRequestParams instance.\n    \n    - parameter text:       The text string to generate an image for.\n    \n    - returns:              A new instance of CLDTextRequestParams.\n    */\n    internal init(text: String) {\n        super.init()\n        setParam(TextParams.Text.rawValue, value: text)\n    }\n    \n    /**\n     Initializes a CLDTextRequestParams instance.\n     \n     - parameter params:    A dictionary of the request parameters.\n     \n     - returns:             A new instance of CLDTextRequestParams.\n     */\n    public init(params: [String : AnyObject]) {\n        super.init()\n        self.params = params\n    }\n    \n    // MARK: Set Params\n    \n    /**\n    Set an identifier that is used for accessing the generated image. \n    If not specified, a unique identifier is generated by Cloudinary.\n    \n    - parameter publicId:   The identifier.\n    \n    - returns:              A new instance of CLDTextRequestParams.\n    */\n    @discardableResult\n    open func setPublicId(_ publicId: String) -> CLDTextRequestParams {\n        setParam(TextParams.PublicId.rawValue, value: publicId)\n        return self\n    }\n    \n    /**\n     Set a font family.\n     \n     - parameter fontFamily:        The name of the font family.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    open func setFontFamily(_ fontFamily: String) -> CLDTextRequestParams {\n        setParam(TextParams.FontFamily.rawValue, value: fontFamily)\n        return self\n    }\n    \n    /**\n     Set the font size in points.\n     \n     - parameter fontSize:          The font size in points. default is 12.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    open func setFontSizeFromInt(_ fontSize: Int) -> CLDTextRequestParams {\n        return setFontSize(String(fontSize))\n    }\n    \n    /**\n     Set the font size in points.\n     \n     - parameter fontSize:          The font size in points. default is 12.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    open func setFontSize(_ fontSize: String) -> CLDTextRequestParams {\n        setParam(TextParams.FontSize.rawValue, value: fontSize)\n        return self\n    }\n    \n    /**\n     Set the font size in points.\n     \n     - parameter fontColor:         A name or RGB representation of the font's color. For example: `red` or #ff0000. default is black.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    open func setFontColor(_ fontColor: String) -> CLDTextRequestParams {\n        setParam(TextParams.FontColor.rawValue, value: fontColor)\n        return self\n    }\n    \n    /**\n     Set the font weight.\n     \n     - parameter fontWeight:        The font weight to set. default is normal.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    @objc(setFontWeightFromFontWeight:)\n    open func setFontWeight(_ fontWeight: CLDFontWeight) -> CLDTextRequestParams {\n        return setFontWeight(String(describing: fontWeight))\n    }\n    \n    /**\n     Set the font weight.\n     \n     - parameter fontWeight:        The font weight to set. default is normal.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    open func setFontWeight(_ fontWeight: String) -> CLDTextRequestParams {\n        setParam(TextParams.FontWeight.rawValue, value: fontWeight)\n        return self\n    }\n    \n    /**\n     Set the font style.\n     \n     - parameter fontStyle:        The font style to set. default is normal.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    @objc(setFontStyleFromFontStyle:)\n    open func setFontStyle(_ fontStyle: CLDFontStyle) -> CLDTextRequestParams {\n        return setFontStyle(String(describing: fontStyle))\n    }\n    \n    /**\n     Set the font style.\n     \n     - parameter fontStyle:        The font style to set. default is normal.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    open func setFontStyle(_ fontStyle: String) -> CLDTextRequestParams {\n        setParam(TextParams.FontStyle.rawValue, value: fontStyle)\n        return self\n    }\n    \n    /**\n     Set the background color.\n     \n     - parameter background:    A name or RGB representation of the background color. For example: `red` or #ff0000. default is transparent.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    open func setBackground(_ background: String) -> CLDTextRequestParams {\n        setParam(TextParams.Background.rawValue, value: background)\n        return self\n    }\n    \n    /**\n     Set the text opacity level from 0 to 100.\n     \n     - parameter opacity:           The text opacity value between 0 (invisible) and 100. default is 100.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    open func setOpacity(_ opacity: Int) -> CLDTextRequestParams {\n        setParam(TextParams.Opacity.rawValue, value: opacity)\n        return self\n    }\n    \n    /**\n     Set a text decoration to add the the generated text, for example: underline.\n     \n     - parameter textDecoration:    The text decoration to set. default is none.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    @objc(setTextDecorationFromTextDecoration:)\n    open func setTextDecoration(_ textDecoration: CLDTextDecoration) -> CLDTextRequestParams {\n        return setTextDecoration(String(describing: textDecoration))\n    }\n    \n    /**\n     Set a text decoration to add the the generated text, for example: underline.\n     \n     - parameter textDecoration:    The text decoration to set. default is none.\n     \n     - returns:                     A new instance of CLDTextRequestParams.\n     */\n    @discardableResult\n    open func setTextDecoration(_ textDecoration: String) -> CLDTextRequestParams {\n        setParam(TextParams.TextDecoration.rawValue, value: textDecoration)\n        return self\n    }\n    \n    \n    \n    fileprivate enum TextParams: String {\n        case Text =                 \"text\"\n        case PublicId =             \"public_id\"\n        case FontFamily =           \"font_family\"\n        case FontSize =             \"font_size\"\n        case FontColor =            \"font_color\"\n        case FontWeight =           \"font_weight\"\n        case FontStyle =            \"font_style\"\n        case Background =           \"background\"\n        case Opacity =              \"opacity\"\n        case TextDecoration =       \"text_decoration\"\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Results/CLDDeleteResult.swift",
    "content": "//\n//  CLDDeleteResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDDeleteResult: CLDBaseResult {\n       \n    // MARK: - Getters\n    \n    open var result: String? {\n        return getParam(.result) as? String\n    }\n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: DeleteResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum DeleteResultKey: CustomStringConvertible {\n        case result\n        \n        var description: String {\n            switch self {\n            case .result:       return \"result\"\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Results/CLDExplicitResult.swift",
    "content": "//\n//  CLDExplicitResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objc open class CLDExplicitResult: CLDUploadResult {\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Results/CLDExplodeResult.swift",
    "content": "//\n//  CLDExplodeResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDExplodeResult: CLDBaseResult {\n    \n    // MARK: - Getters\n    \n    open var status: String? {\n        return getParam(.status) as? String\n    }\n    \n    open var batchId: String? {\n        return getParam(.batchId) as? String\n    }\n    \n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: ExplodeResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum ExplodeResultKey: CustomStringConvertible {\n        case status, batchId\n        \n        var description: String {\n            switch self {\n            case .status:           return \"status\"\n            case .batchId:          return \"batch_id\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Results/CLDMultiResult.swift",
    "content": "//\n//  CLDMultiResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDMultiResult: CLDBaseResult {\n    \n    \n    // MARK: - Getters\n    \n    open var url: String? {\n        return getParam(.url) as? String\n    }\n    \n    open var secureUrl: String? {\n        return getParam(.secureUrl) as? String\n    }\n    \n    open var publicId: String? {\n        return getParam(.publicId) as? String\n    }\n    \n    open var version: String? {\n        guard let version = getParam(.version) else {\n            return nil\n        }\n        return String(describing: version)\n    }    \n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Results/CLDRenameResult.swift",
    "content": "//\n//  CLDRenameResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDRenameResult: CLDBaseResult {\n    \n    // MARK: - Getters\n    \n    open var publicId: String? {\n        return getParam(.publicId) as? String\n    }\n    \n    open var format: String? {\n        return getParam(.format) as? String\n    }\n    \n    open var version: String? {\n        guard let version = getParam(.version) else {\n            return nil\n        }\n        return String(describing: version)\n    }\n    \n    open var resourceType: String? {\n        return getParam(.resourceType) as? String\n    }\n    \n    open var type: String? {\n        return getParam(.urlType) as? String\n    }\n    \n    open var createdAt: String? {\n        return getParam(.createdAt) as? String\n    }\n    \n    open var length: Double? {\n        return getParam(.length) as? Double\n    }\n    \n    open var width: Int? {\n        return getParam(.width) as? Int\n    }\n    \n    open var height: Int? {\n        return getParam(.height) as? Int\n    }\n    \n    open var url: String? {\n        return getParam(.url) as? String\n    }\n    \n    open var secureUrl: String? {\n        return getParam(.secureUrl) as? String\n    }\n    \n    open var nextCursor: String? {\n        return getParam(.nextCursor) as? String\n    }\n    \n    open var exif: [String : String]? {\n        return getParam(.exif) as? [String : String]\n    }\n    \n    open var metadata: [String : String]? {\n        return getParam(.metadata) as? [String : String]\n    }\n\n    open var metadataObject: [String: String]? {\n        return getParam(.metadata_object) as? [String: String]\n    }\n\n    open var faces: AnyObject? {\n        return getParam(.faces)\n    }\n    \n    open var colors: AnyObject? {\n        return getParam(.colors)\n    }\n    \n    open var derived: CLDDerived? {\n        guard let derived = getParam(.derived) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDDerived(json: derived)\n    }\n    \n    open var tags: [String]? {\n        return getParam(.tags) as? [String]\n    }\n    \n    open var moderation: AnyObject? {\n        return getParam(.moderation)\n    }\n    \n    open var context: AnyObject? {\n        return getParam(.context)\n    }\n    \n    open var phash: String? {\n        return getParam(.phash) as? String\n    }\n    \n    open var predominant: CLDPredominant? {\n        guard let predominant = getParam(.predominant) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDPredominant(json: predominant)\n    }\n    \n    open var coordinates: CLDCoordinates? {\n        guard let coordinates = getParam(RenameResultKey.coordinates) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDCoordinates(json: coordinates)\n    }\n    \n    open var info: CLDInfo? {\n        guard let info = getParam(.info) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDInfo(json: info)\n    }\n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: RenameResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n\n    fileprivate enum RenameResultKey: CustomStringConvertible {\n        case nextCursor, derived, predominant, coordinates\n        \n        var description: String {\n            switch self {\n            case .nextCursor:       return \"next_cursor\"\n            case .derived:          return \"derived\"            \n            case .predominant:      return \"predominant\"\n            case .coordinates:      return \"coordinates\"\n            }\n        }\n    }\n}\n\n\n// MARK: - CLDCoordinates\n\n@objcMembers open class CLDCoordinates: CLDBaseResult {\n    \n    open var custom: AnyObject? {\n        return getParam(.custom)\n    }\n    \n    open var faces: AnyObject? {\n        return getParam(.faces)\n    }\n    \n    // MARK: Private Helpers\n    \n    fileprivate func getParam(_ param: CLDCoordinatesKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDCoordinatesKey: CustomStringConvertible {\n        case custom\n        \n        var description: String {\n            switch self {\n            case .custom:           return \"custom\"\n            }\n        }\n    }\n}\n\n\n// MARK: - CLDPredominant\n\n@objcMembers open class CLDPredominant: CLDBaseResult {\n    \n    open var google: AnyObject? {\n        return getParam(.google)\n    }\n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: CLDPredominantKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDPredominantKey: CustomStringConvertible {\n        case google\n        \n        var description: String {\n            switch self {\n            case .google:           return \"google\"\n            }\n        }\n    }\n}\n\n\n// MARK: - CLDDerived\n\n@objcMembers open class CLDDerived: CLDBaseResult {\n    \n    open var transformation: String? {\n        return getParam(.transformation) as? String\n    }\n    \n    open var format: String? {\n        return getParam(.format) as? String\n    }\n    \n    open var length: Double? {\n        return getParam(.length) as? Double\n    }\n    \n    open var identifier: String? {\n        return getParam(.id) as? String\n    }\n    \n    open var url: String? {\n        return getParam(.url) as? String\n    }\n    \n    open var secureUrl: String? {\n        return getParam(.secureUrl) as? String\n    }\n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: CLDDerivedKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum CLDDerivedKey: CustomStringConvertible {\n        case transformation, id\n        \n        var description: String {\n            switch self {\n            case .transformation:           return \"transformation\"\n            case .id:                       return \"id\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Results/CLDSpriteResult.swift",
    "content": "//\n//  CLDSpriteResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDSpriteResult: CLDBaseResult {\n    \n    // MARK: - Getters\n    \n    open var cssUrl: String? {\n        return getParam(.cssUrl) as? String\n    }\n    \n    open var secureCssUrl: String? {\n        return getParam(.secureCssUrl) as? String\n    }\n    \n    open var imageUrl: String? {\n        return getParam(.imageUrl) as? String\n    }\n    \n    open var jsonUrl: String? {\n        return getParam(.jsonUrl) as? String\n    }\n    \n    open var publicId: String? {\n        return getParam(.publicId) as? String\n    }\n    \n    open var version: String? {\n        guard let version = getParam(.version) else {\n            return nil\n        }\n        return String(describing: version)\n    }\n    \n    open var imageInfos: [String : CLDImageInfo]? {\n        guard let imageInfosDic = getParam(.imageInfos) as? [String : AnyObject] else {\n            return nil\n        }\n        var imageInfos: [String : CLDImageInfo] = [:]\n        for key in imageInfosDic.keys {\n            if let imgInfo = imageInfosDic[key] as? [String : AnyObject] {\n                imageInfos[key] = CLDImageInfo(json: imgInfo)\n            }\n        }\n        return imageInfos\n    }\n    \n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: SpriteResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum SpriteResultKey: CustomStringConvertible {\n        case cssUrl, secureCssUrl, imageUrl, jsonUrl, imageInfos\n        \n        var description: String {\n            switch self {\n            case .cssUrl:               return \"css_url\"\n            case .secureCssUrl:         return \"secure_css_url\"\n            case .imageUrl:             return \"image_url\"\n            case .jsonUrl:              return \"json_url\"\n            case .imageInfos:           return \"image_infos\"\n            }\n        }\n    }\n}\n\n\n@objcMembers open class CLDImageInfo: CLDBaseResult {\n    \n    open var x: Int? {\n        return getParam(.x) as? Int\n    }\n    \n    open var y: Int? {\n        return getParam(.y) as? Int\n    }\n    \n    open var width: Int? {\n        return getParam(.width) as? Int\n    }\n    \n    open var height: Int? {\n        return getParam(.height) as? Int\n    }    \n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Results/CLDTagResult.swift",
    "content": "//\n//  CLDTagResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDTagResult: CLDBaseResult {\n    \n    \n    // MARK: - Getters\n    \n    open var publicIds: [String]? {\n        return getParam(.publicIds) as? [String]\n    }\n    \n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: TagResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum TagResultKey: CustomStringConvertible {\n        case publicIds\n        \n        var description: String {\n            switch self {\n            case .publicIds:             return \"public_ids\"\n            }\n        }\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/ManagementApi/Results/CLDTextResult.swift",
    "content": "//\n//  CLDTextResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDTextResult: CLDBaseResult {\n    \n    \n    // MARK: - Getters\n    \n    open var width: Int? {\n        return getParam(.width) as? Int\n    }\n    \n    open var height: Int? {\n        return getParam(.height) as? Int\n    }    \n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/CLDUploaderWidget.swift",
    "content": "//\n//  CLDUploaderWidget.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\nimport AVKit\nimport MobileCoreServices\n\n@objc public protocol CLDUploaderWidgetDelegate: AnyObject {\n    \n    /**\n    Informs the delegate that the upload process will begin for the added requests.\n    \n    - parameter widget:         The widget object.\n    - parameter uploadRequests: The `CLDUploadRequest`s to be uploaded.\n    \n    */\n    func uploadWidget(_ widget: CLDUploaderWidget, willCall uploadRequests: [CLDUploadRequest])\n    \n    /**\n    Informs the delegate that the widget is canceled.\n    \n    - parameter widget:         The widget object.\n    \n    */\n    func widgetDidCancel(_ widget: CLDUploaderWidget)\n    \n    /**\n    Informs the delegate that the widget view is dismissed.\n    \n    - parameter widget:         The widget object.\n    \n    */\n    func uploadWidgetDidDismiss()\n}\n\n@objcMembers public class CLDUploaderWidget: NSObject {\n    \n    public private(set) weak var rootViewController    : UIViewController!\n    public private(set)      var cloudinaryObject      : CLDCloudinary\n    public private(set)      var configuration         : CLDWidgetConfiguration?\n    public private(set)      var images                : [UIImage]\n    public private(set)      var videos                : [AVPlayerItem]\n    private                  var widgetViewController  : CLDWidgetViewController!\n    private                  var widgetPresented       : Bool\n    private                  var imagePicker           : UIImagePickerController!\n    public              weak var delegate              : CLDUploaderWidgetDelegate?\n    \n    private var selectAssetFromLibrary: Bool {\n         self.images.count == 0 && self.videos.count == 0\n    }\n    \n    // MARK - public methods\n    /**\n    Initializes the `CLDUploaderWidget` instance with the specified cloudinary, configuration, images and delegate.\n     \n    - parameter cloudinary:             The CLDCloudinary object to be used for uploading the selected assets.\n    - parameter configuration:          The configuration used by this CLDUploaderWidget instance.\n    - parameter images:                 The images to be presented, edited and uploaded.\n    - parameter delegate:               The delegate object conforming to `CLDUploaderWidgetDelegate`.\n    \n    - returns: The new `CLDUploaderWidget` instance.\n    */\n    convenience public init(\n        cloudinary: CLDCloudinary,\n        configuration: CLDWidgetConfiguration?,\n        images: [UIImage]?,\n        delegate: CLDUploaderWidgetDelegate?\n    ) {\n        self.init(cloudinary: cloudinary, configuration: configuration, images: images, videos: nil, delegate: delegate)\n    }\n    \n    /**\n    Initializes the `CLDUploaderWidget` instance with the specified cloudinary, configuration, images, videos and delegate.\n     \n    - parameter cloudinary:             The CLDCloudinary object to be used for uploading the selected assets.\n    - parameter configuration:          The configuration used by this CLDUploaderWidget instance.\n    - parameter images:                 The images to be presented, edited and uploaded.\n    - parameter videos:                 The videos to be presented and uploaded.\n    - parameter delegate:               The delegate object conforming to `CLDUploaderWidgetDelegate`.\n    \n    - returns: The new `CLDUploaderWidget` instance.\n    */\n    public init(\n        cloudinary: CLDCloudinary,\n        configuration: CLDWidgetConfiguration?,\n        images: [UIImage]?,\n        videos: [AVPlayerItem]?,\n        delegate: CLDUploaderWidgetDelegate?\n    ) {\n        \n        self.cloudinaryObject       = cloudinary\n        self.configuration          = configuration\n        self.images                 = images != nil ? images! : [UIImage]()\n        self.videos                 = videos != nil ? videos! : [AVPlayerItem]()\n        self.delegate               = delegate\n        self.widgetPresented        = false\n        \n        super.init()\n    }\n    \n    /**\n    Sets the CLDCloudinary object to be used for uploading the selected assets\n    \n    - parameter cloudinary:        The cloudinary object.\n    \n    - returns:                     The same instance of CLDUploaderWidget.\n    */\n    @objc(setCloudinaryFromCloudinary:)\n    @discardableResult\n    public func setCloudinary(_ cloudinary: CLDCloudinary) -> Self {\n        \n        guard widgetPresented == false else {\n            print(\"cloudinary can not be set while widget is presented\")\n            return self\n        }\n        \n        self.cloudinaryObject = cloudinary\n        return self\n    }\n    \n    /**\n    Holds the configuration parameters to be used by the `CLDUpladerWidget` instance.\n    \n    - parameter configuration:     The configuration object.\n    \n    - returns:                     The same instance of CLDUploaderWidget.\n    */\n    @objc(setConfigurationFromConfiguration:)\n    @discardableResult\n    public func setConfiguration(_ configuration: CLDWidgetConfiguration) -> Self {\n        \n        guard widgetPresented == false else {\n            print(\"configuration can not be set while widget is presented\")\n            return self\n        }\n        \n        self.configuration = configuration\n        return self\n    }\n    \n    /**\n    Sets images to be presented, edited and uploaded.\n    \n    - parameter images:            The images array object.\n    \n    - returns:                     The same instance of CLDUploaderWidget.\n    */\n    @objc(setImagesFromImages:)\n    @discardableResult\n    public func setImages(_ images: [UIImage]) -> Self {\n        \n        guard widgetPresented == false else {\n            print(\"images can not be set while widget is presented\")\n            return self\n        }\n        \n        self.images = images\n        return self\n    }\n    \n    /**\n    Sets videos to be presented and uploaded.\n    \n    - parameter videos:            The videos array object.\n    \n    - returns:                     The same instance of CLDUploaderWidget.\n    */\n    @objc(setVideosFromVideoItems:)\n    @discardableResult\n    public func setVideos(_ videoItems: [AVPlayerItem]) -> Self {\n        \n        guard widgetPresented == false else {\n            print(\"videos can not be set while widget is presented\")\n            return self\n        }\n        \n        self.videos = videoItems\n        return self\n    }\n    \n    /**\n    Sets videos to be presented and uploaded.\n    \n    - parameter videos:            The videos array object.\n    \n    - returns:                     The same instance of CLDUploaderWidget.\n    */\n    @objc(setVideosFromVideoUrls:)\n    @discardableResult\n    public func setVideos(_ videoUrls: [URL]) -> Self {\n        \n        guard widgetPresented == false else {\n            print(\"videos can not be set while widget is presented\")\n            return self\n        }\n        \n        let videoItems = videoUrls.compactMap {\n            AVPlayerItem(url: $0)\n        }\n                \n        self.videos = videoItems\n        return self\n    }\n    \n    /**\n    Sets a delegate object conforming to `CLDUploaderWidgetDelegate` protocol to recieve information via delegate methods.\n    \n    - parameter delegate:          The delegate object.\n    \n    - returns:                     The same instance of CLDUploaderWidget.\n    */\n    @objc(setDelegateFromDelegate:)\n    @discardableResult\n    public func setDelegate(_ delegate: CLDUploaderWidgetDelegate) -> Self {\n        \n        self.delegate = delegate\n        return self\n    }\n    \n    /**\n    Modally presenting the widget or an `UIImagePickerController` from the given view controller.\n    \n    - parameter viewController:    The presenting `UIViewController` object.\n    */\n    public func presentWidget(from viewController: UIViewController) {\n        \n        let viewControllerToPresent: UIViewController\n        \n        if selectAssetFromLibrary {\n            imagePicker = createImagePicker()\n            viewControllerToPresent = imagePicker\n        }\n        else {\n            widgetViewController    = createWidgetViewController()\n            viewControllerToPresent = widgetViewController\n        }\n        \n        if #available(iOS 9.0, *) {\n            viewControllerToPresent.loadViewIfNeeded()\n        }\n        else {\n            _ = viewController.view\n        }\n        viewControllerToPresent.modalPresentationStyle = .fullScreen\n        \n        if #available(iOS 13.0, *) {\n            viewControllerToPresent.isModalInPresentation = true\n        }\n        \n        rootViewController = viewController\n        rootViewController.present(viewControllerToPresent, animated: true, completion: nil)\n    }\n    \n    /**\n    Dismisses the widget.\n    */\n    public func dismissWidget() {\n        \n        if selectAssetFromLibrary {\n            imagePicker.dismiss(animated: true) {\n                self.delegate?.uploadWidgetDidDismiss()\n            }\n        }\n        else {\n            widgetViewController.dismiss(animated: true) {\n                self.delegate?.uploadWidgetDidDismiss()\n            }\n        }\n    }\n    \n    // MARK - private methods\n    private func createWidgetViewController() -> CLDWidgetViewController {\n        \n        let imageContainers = images.compactMap {\n            CLDWidgetAssetContainer(originalImage: $0, editedImage: $0)\n        }\n        let videoContainers = videos.compactMap {\n            CLDWidgetAssetContainer(videoItem: $0)\n        }\n        \n        let assetContainers = videoContainers + imageContainers\n        \n        return CLDWidgetViewController(assets: assetContainers, configuration: configuration, delegate: self)\n    }\n    \n    private func createImagePicker() -> UIImagePickerController {\n        \n        let picker = UIImagePickerController()\n        picker.delegate = self\n        picker.sourceType = .photoLibrary\n        picker.mediaTypes = [kUTTypeImage as String, kUTTypeMovie as String]\n\n        return picker\n    }\n    \n    private func upload(assets: [CLDWidgetAssetContainer]) -> [CLDUploadRequest] {\n        \n        let images = assets.filter {\n            $0.assetType == .image\n        }\n        \n        let videos = assets.filter {\n            $0.assetType == .video\n        }\n        \n        let imagesUploadRequests = upload(images: images)\n        let videosUploadRequests = upload(videos: videos)\n        \n        return videosUploadRequests + imagesUploadRequests\n    }\n    \n    private func upload(images: [CLDWidgetAssetContainer]) -> [CLDUploadRequest] {\n        \n        guard images.count > 0 else { return [] }\n        \n        let datas = images.compactMap {\n            $0.editedImage?.pngData()\n        }\n        \n        let uploader = cloudinaryObject.createUploader()\n        \n        let requests = datas.compactMap { (data) -> CLDUploadRequest? in\n           \n            // unsigned upload must have a preset\n            if let configuration = configuration,\n                configuration.uploadType.signed == false,\n                let preset = configuration.uploadType.preset {\n                \n                return uploader.upload(data: data, uploadPreset: preset).response {\n                    (result, error) in\n                    print(\"image unsigned result \\(String(describing: result))\")\n                    print(\"image unsigned error  \\(String(describing: error))\")\n                }\n            }\n            else {\n                // default upload type\n                return uploader.signedUpload(data: data).response { (result, error) in\n                    print(\"image signed result \\(String(describing: result))\")\n                    print(\"image signed error  \\(String(describing: error))\")\n                }\n            }\n        }\n        \n        return requests\n    }\n    \n    private func upload(videos: [CLDWidgetAssetContainer]) -> [CLDUploadRequest] {\n        \n        guard videos.count > 0 else { return [] }\n        \n        let videosUrls = videos.compactMap {\n            ($0.originalVideo?.asset as? AVURLAsset)?.url\n        }\n        \n        let params   = CLDUploadRequestParams()\n        params.setResourceType(.video)\n        let uploader = cloudinaryObject.createUploader()\n        \n        let requests = videosUrls.compactMap { (url) -> CLDUploadRequest? in\n           \n            // unsigned upload must have a preset\n            if let configuration = configuration,\n                configuration.uploadType.signed == false,\n                let preset = configuration.uploadType.preset {\n                \n                return uploader.upload(url: url, uploadPreset: preset, params: params).response {\n                    (result, error) in\n                    print(\"video unsigned result \\(String(describing: result))\")\n                    print(\"video unsigned error  \\(String(describing: error))\")\n                }\n            }\n            else {\n                \n                // default upload type\n                return uploader.signedUpload(url: url, params: params).response { (result, error) in\n                    print(\"video signed result \\(String(describing: result))\")\n                    print(\"video signed error  \\(String(describing: error))\")\n                }\n            }\n        }\n        \n        return requests\n    }\n}\n\n// MARK: - UIImagePickerControllerDelegate\nextension CLDUploaderWidget: UIImagePickerControllerDelegate, UINavigationControllerDelegate {\n    \n    public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {\n        \n        if let image = info[.originalImage] as? UIImage {\n            images = [image]\n        }\n        else if let videoUrl = info[.mediaURL] as? URL {\n            let playerItem = AVPlayerItem(url: videoUrl)\n            videos = [playerItem]\n        }\n        else {\n            dismissWidget()\n            return\n        }\n    \n        widgetViewController = createWidgetViewController()\n        picker.pushViewController(widgetViewController, animated: true)\n    }\n    \n    public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {\n        delegate?.widgetDidCancel(self)\n        dismissWidget()\n    }\n}\n\n// MARK: - CLDWidgetViewControllerDelegate\nextension CLDUploaderWidget: CLDWidgetViewControllerDelegate {\n    \n    func widgetViewController(_ controller: CLDWidgetViewController, didFinishEditing editedAssets: [CLDWidgetAssetContainer]) {\n        \n        let uploadRequests = upload(assets: editedAssets)\n        \n        delegate?.uploadWidget(self, willCall: uploadRequests)\n        dismissWidget()\n    }\n    \n    func widgetViewControllerDidCancel(_ controller: CLDWidgetViewController) {\n        delegate?.widgetDidCancel(self)\n        dismissWidget()\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/CropView/CLDCropOverlayView.swift",
    "content": "//\n//  CLDCropOverlayView.swift\n//  ProjectCLDWidgetEditViewController\n//\n//  Created by Arkadi Yoskovitz on 8/17/20.\n//  Copyright © 2020 Gini-Apps LTD. All rights reserved.\n//\n\nimport UIKit\n\nprivate let kCLDCropOverLayerPlaceholder = CGFloat(00.0);\nprivate let kCLDCropOverLayerCornerWidth = CGFloat(20.0);\n\n@objc\n@objcMembers\npublic class CLDCropOverlayView : UIView\n{\n    // MARK: -\n    public override var frame: CGRect { didSet { layoutLinesIfNeeded() } }\n    \n    public var gridColor : UIColor { didSet { layoutLinesIfNeeded() } }\n    public var knobColor : UIColor { didSet { layoutLinesIfNeeded() } }\n    \n    // MARK: - Public Properties\n    \n    /**\n     Hides the interior grid lines, sans animation.\n     */\n    public var isGridHidden : Bool {\n        set { setGridlines(hidden: newValue, animted: false) }\n        get { areGridLinesHidden }\n    }\n    \n    /**\n     Add/Remove the interior horizontal grid lines.\n     */\n    public var shouldDisplayHorizontalGridLines : Bool {\n        set { setDisplayHorizontalGridLines(newValue) }\n        get { displayGridLinesHorizontal }\n    }\n    \n    /**\n     Add/Remove the interior vertical grid lines.\n     */\n    public var shouldDisplayVerticalGridLines : Bool {\n        set { setDisplayVerticalGridLines(newValue) }\n        get { displayGridLinesVertical }\n    }\n    \n    // MARK: - Private Properties\n    \n    private var areGridLinesHidden        : Bool\n    private var displayGridLinesHorizontal: Bool\n    private var displayGridLinesVertical  : Bool\n    \n    private var gridLinesHorizontal : [UIView]\n    private var gridLinesVertical   : [UIView]\n    \n    private var outerLineViews       : [UIView] // top, right, bottom, left\n    \n    private var    topLeftLineViews  : [UIView] // vertical, horizontal\n    private var bottomLeftLineViews  : [UIView]\n    private var bottomRightLineViews : [UIView]\n    private var    topRightLineViews : [UIView]\n    \n    // MARK: - init\n    public override init(frame: CGRect) {\n        self.areGridLinesHidden = false\n        \n        self.displayGridLinesVertical   = true\n        self.displayGridLinesHorizontal = true\n        \n        self.gridColor = UIColor.white\n        self.knobColor = UIColor.white\n        \n        self.gridLinesHorizontal = [UIView]()\n        self.gridLinesVertical   = [UIView]()\n        \n        self.outerLineViews    = [UIView]() //top, right, bottom, left\n        self.topLeftLineViews  = [UIView]()\n        self.topRightLineViews = [UIView]()\n        self.bottomLeftLineViews  = [UIView]()\n        self.bottomRightLineViews = [UIView]()\n        \n        super.init(frame: frame)\n        \n        self.clipsToBounds = false\n        \n        self.outerLineViews.append(contentsOf: [\n            createLineView(background: gridColor),\n            createLineView(background: gridColor),\n            createLineView(background: gridColor),\n            createLineView(background: gridColor)\n        ])\n        \n        self.topLeftLineViews.append(contentsOf: [\n            createLineView(background: gridColor),\n            createLineView(background: gridColor)\n        ])\n        self.topRightLineViews.append(contentsOf: [\n            createLineView(background: gridColor),\n            createLineView(background: gridColor)\n        ])\n        self.bottomLeftLineViews.append(contentsOf: [\n            createLineView(background: gridColor),\n            createLineView(background: gridColor)\n        ])\n        self.bottomRightLineViews.append(contentsOf: [\n            createLineView(background: gridColor),\n            createLineView(background: gridColor)\n        ])\n        self.setDisplayHorizontalGridLines(true)\n        self.setDisplayVerticalGridLines(true)\n    }\n    \n    required init?(coder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    // MARK: -\n    public override func didMoveToSuperview() {\n        super.didMoveToSuperview()\n        layoutLinesIfNeeded()\n    }\n    \n    // MARK: -\n    /**\n     Shows and hides the interior grid lines with an optional crossfade animation.\n     */\n    public func setGridlines(hidden: Bool, animted: Bool) {\n        \n        areGridLinesHidden = hidden;\n        \n        let block : () -> Void = {\n            self.gridLinesHorizontal.forEach { $0.alpha = hidden ? 0.0 : 1.0 }\n            self.gridLinesVertical.forEach { $0.alpha = hidden ? 0.0 : 1.0 }\n        }\n        \n        switch animted {\n        case true : UIView.animate(withDuration: hidden ? 0.35 : 0.2) { block() }\n        case false: block()\n        }\n    }\n    \n    // MARK: - Private setter actions\n    private func setDisplayHorizontalGridLines(_ display: Bool) {\n        \n        displayGridLinesHorizontal = display\n        \n        gridLinesHorizontal.forEach { $0.removeFromSuperview() }\n        \n        gridLinesHorizontal.removeAll()\n        \n        if displayGridLinesHorizontal {\n            gridLinesHorizontal.append(contentsOf: [\n                createLineView(background: gridColor),\n                createLineView(background: gridColor)\n            ])\n        }\n        setNeedsDisplay()\n    }\n    \n    private func setDisplayVerticalGridLines(_ display: Bool) {\n        \n        displayGridLinesVertical = display\n        \n        gridLinesVertical.forEach { $0.removeFromSuperview() }\n        \n        gridLinesVertical.removeAll()\n        \n        if displayGridLinesVertical {\n            gridLinesVertical.append(contentsOf: [\n                createLineView(background: gridColor),\n                createLineView(background: gridColor)\n            ])\n        }\n        setNeedsDisplay()\n    }\n    \n    // MARK: - Private methods\n    private func layoutLinesIfNeeded() {\n        \n        guard !outerLineViews.isEmpty else { return }\n        applyLayoutLines()\n    }\n    \n    private func applyLayoutLines() {\n        \n        let boundsSize = bounds.size\n        \n        // Border lines\n        outerLineViews.enumerated().forEach { (item) in\n            \n            let aRect : CGRect\n            switch item.offset {\n            case 0: aRect = CGRect(x:  0.0            , y:              -1.0, width: boundsSize.width + 2.0, height:  1.0) // Top\n            case 1: aRect = CGRect(x: boundsSize.width, y:               0.0, width: 1.0, height: boundsSize.height + 0.0) // Right\n            case 2: aRect = CGRect(x: -1.0            , y: boundsSize.height, width: boundsSize.width + 2.0, height:  1.0) // Bottom\n            case 3: aRect = CGRect(x: -1.0            , y:               0.0, width: 1.0, height: boundsSize.height + 1.0) // Left\n            default: aRect = CGRect.zero\n            }\n            item.element.frame = aRect\n        }\n        \n        // Corner liness\n        [topLeftLineViews, topRightLineViews, bottomRightLineViews, bottomLeftLineViews].enumerated().forEach { item in\n            var VFrame = CGRect.zero\n            var HFrame = CGRect.zero\n            \n            switch item.offset {\n            case 0: // Top left\n                VFrame = CGRect(x: kCLDCropOverLayerPlaceholder - 3.0,\n                                y: kCLDCropOverLayerPlaceholder - 3.0,\n                                width: 3.0, height: kCLDCropOverLayerCornerWidth + 3.0)\n                HFrame = CGRect(x: kCLDCropOverLayerPlaceholder + 0.0,\n                                y: kCLDCropOverLayerPlaceholder - 3.0,\n                                width: kCLDCropOverLayerCornerWidth + 0.0, height: 3.0)\n                break\n                \n            case 1: // Top right\n                VFrame = CGRect(x: boundsSize.width + kCLDCropOverLayerPlaceholder,\n                                y: kCLDCropOverLayerPlaceholder - 3.0,\n                                width: 3.0, height: kCLDCropOverLayerCornerWidth + 3.0)\n                HFrame = CGRect(x: boundsSize.width - kCLDCropOverLayerCornerWidth,\n                                y: kCLDCropOverLayerPlaceholder - 3.0,\n                                width: kCLDCropOverLayerCornerWidth + 0.0, height: 3.0)\n                break\n                \n            case 2: // Bottom right\n                VFrame = CGRect(x: boundsSize.width  + kCLDCropOverLayerPlaceholder,\n                                y: boundsSize.height - kCLDCropOverLayerCornerWidth,\n                                width: 3.0, height: kCLDCropOverLayerCornerWidth + 3.0)\n                HFrame = CGRect(x: boundsSize.width  - kCLDCropOverLayerCornerWidth,\n                                y: boundsSize.height + kCLDCropOverLayerPlaceholder,\n                                width: kCLDCropOverLayerCornerWidth + 0.0, height: 3.0)\n                break\n                \n            case 3: // Bottom left\n                VFrame = CGRect(x: kCLDCropOverLayerPlaceholder - 3.0,\n                                y: boundsSize.height - kCLDCropOverLayerCornerWidth,\n                                width: 3.0, height: kCLDCropOverLayerCornerWidth)\n                HFrame = CGRect(x: kCLDCropOverLayerPlaceholder - 3.0,\n                                y: boundsSize.height + kCLDCropOverLayerPlaceholder,\n                                width: kCLDCropOverLayerCornerWidth + 3.0, height: 3.0)\n                break\n            default:\n                break\n            }\n            item.element[0].frame = VFrame\n            item.element[1].frame = HFrame\n        }\n        \n        var    padding : CGFloat\n        var linesCount : Int\n        let thickness  = 1.0 / UIScreen.main.scale\n        \n        // Grid lines - horizontal\n        linesCount = gridLinesHorizontal.count\n        padding    = (bounds.height - (thickness * CGFloat(linesCount))) / (CGFloat(linesCount) + 1.0)\n        gridLinesHorizontal.enumerated().forEach { item in\n            \n            var aRect = CGRect.zero\n            aRect.size.width  = bounds.width\n            aRect.size.height = thickness\n            aRect.origin.y    = (padding * CGFloat(item.offset + 1)) + (thickness * CGFloat(item.offset))\n            item.element.frame = aRect\n        }\n        \n        // Grid lines - vertical\n        linesCount = gridLinesVertical.count\n        padding    = (bounds.width - (thickness * CGFloat(linesCount))) / (CGFloat(linesCount) + 1.0)\n       \n        gridLinesVertical.enumerated().forEach { item in\n            \n            var aRect = CGRect.zero\n            aRect.size.width  = thickness\n            aRect.size.height = bounds.height\n            aRect.origin.x    = (padding * CGFloat(item.offset + 1)) + (thickness * CGFloat(item.offset))\n            item.element.frame = aRect\n        }\n    }\n    \n    private func createLineView(background color: UIColor) -> UIView {\n        \n        let newLine = UIView(frame: .zero)\n        newLine.backgroundColor = color\n        addSubview(newLine)\n        return newLine\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/CropView/CLDCropScrollView.swift",
    "content": "//\n//  CLDCropScrollView.swift\n//  ProjectCLDWidgetEditViewController\n//\n//  Created by Arkadi Yoskovitz on 8/17/20.\n//  Copyright © 2020 Gini-Apps LTD. All rights reserved.\n//\n\nimport UIKit\npublic typealias CLDTouchHandler = () -> Void\n\n/*\n Subclassing UIScrollView was necessary in order to directly capture\n touch events that weren't otherwise accessible via UIGestureRecognizer objects.\n */\n@objc\n@objcMembers\npublic class CLDCropScrollView : UIScrollView {\n    \n    public var touchesBegan    :CLDTouchHandler?\n    public var touchesCancelled:CLDTouchHandler?\n    public var touchesEnded    :CLDTouchHandler?\n    \n    override init(frame: CGRect) {\n        super.init(frame: frame)\n        configureInitialState()\n    }\n    \n    required init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n        configureInitialState()\n    }\n    \n    private func configureInitialState() {\n        \n        self.autoresizingMask = [.flexibleHeight , .flexibleWidth]\n        self.alwaysBounceHorizontal = true\n        self.alwaysBounceVertical   = true\n        self.showsHorizontalScrollIndicator = false\n        self.showsVerticalScrollIndicator   = false\n    }\n    \n    public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {\n        if let handler = touchesBegan {\n            handler()\n        }\n        super.touchesBegan(touches, with: event)\n    }\n    \n    public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {\n        if let handler = touchesEnded {\n            handler()\n        }\n        super.touchesEnded(touches, with: event)\n    }\n    \n    public override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {\n        if let handler = touchesEnded {\n            handler()\n        }\n        super.touchesCancelled(touches, with: event)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/CropView/CLDCropScrollViewController.swift",
    "content": "//\n//  CLDCropViewScrollViewDelegate.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nclass CLDCropScrollViewController: NSObject, UIScrollViewDelegate {\n    \n    weak var cropView: CLDCropView!\n    \n    init(cropView: CLDCropView) {\n        self.cropView = cropView\n        super.init()\n    }\n    \n    func viewForZooming(in scrollView: UIScrollView) -> UIView? {\n        \n        return cropView.backgroundContainerView\n    }\n    \n    func scrollViewDidScroll(_ scrollView: UIScrollView) {\n        \n        cropView.matchForegroundToBackground()\n    }\n    \n    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {\n        \n        cropView.startEditing()\n        cropView.isResettable = true\n    }\n    \n    func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {\n        \n        cropView.startEditing()\n        cropView.isResettable = true\n    }\n    \n    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {\n        \n        cropView.startResetTimer()\n        cropView.checkForCanReset()\n    }\n    \n    func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {\n        \n        cropView.startResetTimer()\n        cropView.checkForCanReset()\n    }\n    \n    func scrollViewDidZoom(_ scrollView: UIScrollView) {\n        \n        if scrollView.isTracking {\n            cropView.cropBoxLastEditedZoomScale    = scrollView.zoomScale\n            cropView.cropBoxLastEditedMinZoomScale = scrollView.minimumZoomScale\n        }\n        cropView.matchForegroundToBackground()\n    }\n    \n    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {\n        \n        if !decelerate {\n            cropView.startResetTimer()\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/CropView/CLDCropView.swift",
    "content": "//\n//  CLDCropView.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\npublic extension CGFloat {\n    \n    static var ulpOfOne: CGFloat { CGFloat(Float.ulpOfOne) }\n}\n\n/**\n Preset values of the most common aspect ratios that can be used to quickly configure\n the crop view controller.\n */\n@objc\npublic enum CLDCropViewControllerAspectRatioPreset : Int {\n    case original\n    case square\n    case rect3x2\n    case rect5x3\n    case rect4x3\n    case rect5x4\n    case rect7x5\n    case rect16x9\n    case custom\n}\n\n/**\n When the user taps down to resize the box, this state is used\n to determine where they tapped and how to manipulate the box\n */\n@objc\npublic enum CLDCropViewOverlayEdge : Int {\n    case none\n    case topLeft\n    case top\n    case topRight\n    case right\n    case bottomRight\n    case bottom\n    case bottomLeft\n    case left\n}\n\n// =====================================================================================================================\n@objc\npublic protocol CLDCropViewDelegate : NSObjectProtocol {\n    @objc optional func cropView(_ cropView: CLDCropView, didChangeResettable state: Bool)\n}\n\n// =====================================================================================================================\n@objc\n@objcMembers\npublic class CLDCropView: UIView {\n    \n    // MARK: - Constants\n    internal struct Constants {\n        internal static let            padding : CGFloat      = CGFloat(14.0)     // kTOCropViewPadding\n        internal static let      timerDuration : TimeInterval = TimeInterval(0.8) // kTOCropTimerDuration\n        internal static let     minimumBoxSize : CGFloat      = CGFloat(42.0)     // kTOCropViewMinimumBoxSize\n        internal static let circularPathRadius : CGFloat      = CGFloat(300.0)    // kTOCropViewCircularPathRadius\n        internal static let   maximumZoomScale : CGFloat      = CGFloat(15.0)     // kTOMaximumZoomScale\n    }\n    \n    // MARK: - Types\n    internal class Calculator {\n        internal class CropBox     {}\n        internal class ImageCrop   {}\n        internal class AspectRatio {}\n    }\n    \n    // MARK: - Properties\n    \n    /**\n     A delegate object that receives notifications from the crop view\n     */\n    public weak var delegate: CLDCropViewDelegate?\n    \n    /**\n     If false, the user cannot resize the crop box frame using a pan gesture from a corner.\n     Default value is true.\n     */\n    public var cropBoxResizeEnabled: Bool {\n        get { _cropBoxResizeEnabled }\n        set {\n            _cropBoxResizeEnabled = newValue\n            gridPanGestureRecognizer.isEnabled = newValue\n        }\n    }\n    \n    /**\n     Inset the workable region of the crop view in case in order to make space for accessory views\n     */\n    public var cropRegionInsets: UIEdgeInsets\n    \n    /**\n     When performing manual content layout (such as during screen rotation), disable any internal layout\n     */\n    public var internalLayoutDisabled: Bool\n    \n    /**\n     A width x height ratio that the crop box will be rescaled to (eg 4:3 is {4.0f, 3.0f})\n     Setting it to CGSizeZero will reset the aspect ratio to the image's own ratio.\n     */\n    public var aspectRatio: CGSize {\n        get { _aspectRatio }\n        set { setAspectRatio(newValue, animated: false) }\n    }\n    \n    /**\n     When the cropping box is locked to its current aspect ratio (But can still be resized)\n     */\n    public var aspectRatioLockEnabled: Bool\n    \n    /**\n     If true, a custom aspect ratio is set, and the aspectRatioLockEnabled is set to YES,\n     the crop box will swap it's dimensions depending on portrait or landscape sized images.\n     This value also controls whether the dimensions can swap when the image is rotated.\n     \n     Default is true.\n     */\n    public var aspectRatioLockDimensionSwapEnabled: Bool\n    \n    /**\n     When the user taps 'reset', whether the aspect ratio will also be reset as well\n     \n     Default is true.\n     */\n    public var resetAspectRatioEnabled: Bool\n    \n    /**\n     The rotation angle of the crop view (Will always be negative as it rotates in a counter-clockwise direction)\n     */\n    public var angle: Int {\n        get { _angle }\n        set {\n            // The initial layout would not have been performed yet.\n            // Save the value and it will be applied when it has\n            \n            var newAngle = newValue\n            \n            if (newValue % 90 != 0) { newAngle = 0 }\n            \n            if !initialSetupPerformed {\n                restoreAngle = newAngle\n                return\n            }\n            \n            // Negative values are allowed, so rotate clockwise or counter clockwise depending on direction\n            if (newAngle >= 0) {\n                while ( labs(angle) !=  labs(newAngle)) { rotateImageNinetyDegreesAnimated(false, clockwise: true ) }\n            } else {\n                while (-labs(angle) != -labs(newAngle)) { rotateImageNinetyDegreesAnimated(false, clockwise: false) }\n            }\n        }\n    }\n    \n    /**\n     In relation to the coordinate space of the image, the frame that the crop view is focusing on\n     */\n    public var imageCropFrame: CGRect {\n        get {\n            return Calculator.ImageCrop.computeFrame(given: imageSize, scrollView: scrollView, cropBox: cropBoxFrame)\n        }\n        set {\n            \n            guard initialSetupPerformed else { restoreImageCropFrame = newValue; return }\n            \n            let adjutsments = Calculator.ImageCrop.computeAdjutsments(for: self,\n                                                                      scrollView: scrollView,\n                                                                      content: contentBounds,\n                                                                      newValue: newValue)\n            \n            cropBoxFrame = adjutsments.cropFrame\n            \n            applyCropFrameAdjutsments(to: scrollView, originPoint: newValue.origin, minimumScale: adjutsments.minimumZoomScale, adjustedZoom: adjutsments.adjustedZoomScale)\n        }\n    }\n    \n    /**\n     Paddings of the crop rectangle.\n     \n     Default to 14.0\n     */\n    public var cropViewPadding: CGFloat\n    \n    /**\n     Delay before crop frame is adjusted according new crop area.\n     \n     Default to 0.8\n     */\n    public var cropAdjustingDelay: TimeInterval\n    \n    /**\n     The minimum croping aspect ratio. If set, user is prevented from setting cropping\n     rectangle to lower aspect ratio than defined by the parameter.\n     */\n    public var minimumAspectRatio: CGFloat\n    \n    /**\n     The maximum scale that user can apply to image by pinching to zoom. Small values\n     are only recomended with aspectRatioLockEnabled set to true.\n     \n     Default to 15.0\n     */\n    public var maximumZoomScale: CGFloat\n    \n    /**\n     Always show the cropping grid lines, even when the user isn't interacting.\n     This also disables the fading animation.\n     \n     (Default is NO)\n     */\n    public var alwaysShowCroppingGrid: Bool {\n        get { _alwaysShowCroppingGrid }\n        set {\n            if _alwaysShowCroppingGrid == newValue { return }\n            _alwaysShowCroppingGrid = newValue\n            gridOverlayView.setGridlines(hidden: !newValue, animted: true)\n        }\n    }\n    \n    /**\n     Permanently hides the translucency effect covering the outside bounds of the\n     crop box.\n     \n     Default is NO\n     */\n    public var translucencyAlwaysHidden: Bool {\n        get { _translucencyAlwaysHidden }\n        set {\n            guard _translucencyAlwaysHidden != newValue else { return }\n            _translucencyAlwaysHidden = newValue\n            translucencyView.isHidden = newValue\n        }\n    }\n    \n    /**\n     The image that the crop view is displaying. This cannot be changed once the crop view is instantiated.\n     */\n    public internal(set) var image : UIImage\n    \n    \n    /* Views */\n    /**\n     The main image view, placed within the scroll view\n     */\n    internal var backgroundImageView: UIImageView!\n    \n    /**\n     A view which contains the background image view, to separate its transforms from the scroll view.\n     */\n    internal var backgroundContainerView: UIView!\n    \n    /**\n     A container view that clips the a copy of the image so it appears over the dimming view\n     */\n    public   private(set) var foregroundContainerView: UIView!\n    \n    /**\n     A copy of the background image view, placed over the dimming views\n     */\n    internal var foregroundImageView: UIImageView!\n    \n    /**\n     The scroll view in charge of panning/zooming the image.\n     */\n    internal private(set) var scrollView: CLDCropScrollView!\n    \n    /**\n     The scroll view in charge of panning/zooming the image.\n     */\n    private var scrollViewDelegate: CLDCropScrollViewController!\n    \n    /**\n     A semi-transparent grey view, overlaid on top of the background image\n     */\n    private var overlayView: UIView!\n    \n    /**\n     A blur view that is made visible when the user isn't interacting with the crop view\n     */\n    internal var translucencyView: UIVisualEffectView!\n    \n    /**\n     The dark blur visual effect applied to the visual effect view.\n     */\n    private var translucencyEffect: UIBlurEffect!\n    \n    /**\n     A grid view overlaid on top of the foreground image view's container.\n     */\n    public  private(set) var gridOverlayView: CLDCropOverlayView!\n    \n    /* Gesture Recognizers */\n    \n    /**\n     The gesture recognizer in charge of controlling the resizing of the crop view\n     */\n    private var gridPanGestureRecognizer: UIPanGestureRecognizer!\n    \n    /* Crop box handling */\n    \n    /**\n     No by default, when setting initialCroppedImageFrame this will be set to YES, and set back to NO after first application - so it's only done once\n     */\n    private var applyInitialCroppedImageFrame: Bool\n    \n    /**\n     The edge region that the user tapped on, to resize the cropping region\n     */\n    internal var tappedEdge: CLDCropViewOverlayEdge\n    \n    /**\n     When resizing, this is the original frame of the crop box.\n     */\n    internal var cropOriginFrame : CGRect\n    \n    /**\n     The initial touch point of the pan gesture recognizer\n     */\n    internal var  panOriginPoint : CGPoint\n    \n    /**\n     The frame of the cropping box in the coordinate space of the crop view\n     */\n    public internal(set) var cropBoxFrame: CGRect {\n        get { _cropBoxFrame }\n        set {\n            if _cropBoxFrame.equalTo(newValue) { return }\n            \n            guard newValue.isValidBoxSize else { return }\n            \n            // Clamp the cropping region to the inset boundaries of the screen\n            _cropBoxFrame = Calculator.CropBox.clampFrame(given: contentBounds, cropBox: newValue,\n                                                          minimumBoxSize: Constants.minimumBoxSize)\n            \n            applyDidSetCropBoxFrame(to: _cropBoxFrame)\n        }\n    }\n    \n    /**\n     A manager for the crop view UI\n     */\n    fileprivate var cropUIManager: CLDCropViewUIManager!\n    \n    /**\n     The timer used to reset the view after the user stops interacting with it\n     */\n    internal var resetTimer: Timer?\n    \n    /**\n     Used to denote the active state of the user manipulating the content\n     default is NO. setting is not animated.\n     */\n    private var isEditing: Bool {\n        get { _isEditing }\n        set {\n            setEditing(newValue, resetCropBox: false, animated: false)\n        }\n    }\n    \n    internal func startEditing() {\n        cancelResetTimer()\n        setEditing(true, resetCropBox: false, animated: true)\n    }\n    \n    internal func setEditing(_ editing: Bool, resetCropBox: Bool, animated: Bool) {\n        \n        if _isEditing == editing { return }\n        _isEditing = editing\n        \n        // Toggle the visiblity of the gridlines when not editing\n        var hidden = !editing\n        if (alwaysShowCroppingGrid) { hidden = false } // Override this if the user requires\n        gridOverlayView.setGridlines(hidden: hidden, animted: animated)\n        \n        if resetCropBox {\n            moveCroppedContentToCenterAnimated(animated)\n            captureStateForImageRotation()\n            cropBoxLastEditedAngle = angle\n        }\n        \n        switch animated {\n        case false:\n            toggleTranslucencyViewVisible(!editing)\n            \n        case true:\n            let duration = editing ? 0.05 : 0.35\n            let delay    = editing ? 0.00 : 0.35\n            \n            UIView.animateKeyframes(withDuration: duration, delay: delay, options: [], animations: {\n                \n                self.toggleTranslucencyViewVisible(!editing)\n                \n            }, completion: nil)\n        }\n    }\n    \n    /**\n     At times during animation, disable matching the forground image view to the background\n     */\n    internal var disableForgroundMatching: Bool\n    \n    /* Pre-screen-rotation state information */\n    private var rotationContentOffset: CGPoint\n    private var rotationContentSize  : CGSize\n    private var rotationBoundFrame   : CGRect\n    \n    /* View State information */\n    /**\n     Give the current screen real-estate, the frame that the scroll view is allowed to use\n     */\n    internal var contentBounds: CGRect {\n        \n        return Calculator.bounds(for: self.bounds, padding: cropViewPadding, cropRegion: cropRegionInsets)\n    }\n    \n    /**\n     Given the current rotation of the image, the size of the image\n     */\n    internal var imageSize: CGSize {\n        \n        if (angle ==  -90 || angle == -270 || angle ==   90 || angle ==  270 )\n        {\n            return CGSize(width: image.size.height, height: image.size.width )\n        }\n        else\n        {\n            return CGSize(width: image.size.width , height: image.size.height)\n        }\n    }\n    \n    /**\n     True if an aspect ratio was explicitly applied to this crop view\n     */\n    internal var hasAspectRatio: Bool {\n        \n        return aspectRatio.width > CGFloat.ulpOfOne && aspectRatio.height > CGFloat.ulpOfOne\n    }\n    \n    /* 90-degree rotation state data */\n    /**\n     When performing 90-degree rotations, remember what our last manual size was to use that as a base\n     */\n    internal var cropBoxLastEditedSize: CGSize\n    \n    /**\n     Remember which angle we were at when we saved the editing size\n     */\n    internal var cropBoxLastEditedAngle: Int\n    \n    /**\n     Remember the zoom size when we last edited\n     */\n    internal var cropBoxLastEditedZoomScale: CGFloat\n    \n    /**\n     Remember the minimum size when we last edited.\n     */\n    internal var cropBoxLastEditedMinZoomScale: CGFloat\n    \n    /**\n     Disallow any input while the rotation animation is playing\n     */\n    internal var rotateAnimationInProgress: Bool\n    \n    /* Reset state data */\n    /**\n     Save the original crop box size so we can tell when the content has been edited\n     */\n    private var originalCropBoxSize: CGSize\n    \n    /**\n     Save the original content offset so we can tell if it's been scrolled.\n     */\n    private var originalContentOffset: CGPoint\n    \n    /**\n     Whether the user has manipulated the crop view to the point where it can be reset\n     */\n    public internal(set) var isResettable: Bool {\n        get{ _isResettableFlag }\n        set{\n            guard newValue != _isResettableFlag else { return }\n            \n            _isResettableFlag = newValue\n            \n            delegate?.cropView?(self, didChangeResettable: _isResettableFlag)\n        }\n    }\n    \n    /**\n     In iOS 9, a new dynamic blur effect became available.\n     */\n    public internal(set) var dynamicBlurEffect: Bool\n    \n    // MARK: -                    ======================================================================================\n\n    /**\n     If restoring to a previous crop setting, these properties hang onto the\n     values until the view is configured for the first time.\n     */\n    private var restoreAngle         : Int\n    private var restoreImageCropFrame: CGRect\n    \n    /**\n     Set to YES once `performInitialLayout` is called.\n     This lets pending properties get queued until the view has been properly set up in its parent.\n     */\n    private var initialSetupPerformed: Bool\n    \n    // MARK: - Private properties ======================================================================================\n    private var _cropBoxFrame            : CGRect\n    private var _cropBoxResizeEnabled    : Bool\n    private var _simpleRenderMode        : Bool\n    private var _imageCropFrame          : CGRect\n    private var _isEditing               : Bool\n    private var _isResettableFlag        : Bool\n    private var _aspectRatio             : CGSize\n    private var _croppingViewsHidden     : Bool\n    private var _gridOverlayHidden       : Bool\n    private var _alwaysShowCroppingGrid  : Bool\n    private var _translucencyAlwaysHidden: Bool\n    \n    var _angle                   : Int\n    \n    // MARK: - Initialized        ======================================================================================\n    \n    /**\n     Create a new instance of the crop view with the specified image and cropping\n     */\n    public init(image: UIImage) {\n        \n        self.image = image\n        \n        self.aspectRatioLockDimensionSwapEnabled = true\n        self.resetAspectRatioEnabled  = true\n        self.cropViewPadding          = Constants.padding\n        self.cropAdjustingDelay       = Constants.timerDuration\n        \n        self.cropBoxLastEditedSize         = CGSize.zero\n        self.cropBoxLastEditedAngle        = 0\n        self.cropBoxLastEditedZoomScale    = 0.0\n        self.cropBoxLastEditedMinZoomScale = 0.0\n        self.rotateAnimationInProgress     = false\n        \n        self.cropRegionInsets   = .zero\n        self.minimumAspectRatio = CGFloat(0.0)\n        self.internalLayoutDisabled = false\n        self.aspectRatioLockEnabled = false\n        \n        self.tappedEdge = .none\n        \n        self.cropOriginFrame = CGRect.zero\n        self.panOriginPoint  = CGPoint.zero\n        \n        self._angle       = 0\n        self._isEditing   = false\n        \n        self._cropBoxFrame   = .zero\n        self._aspectRatio    = .zero\n        self._imageCropFrame = .zero\n        \n        self._isResettableFlag = false\n        \n        self._simpleRenderMode          = false\n        self._cropBoxResizeEnabled      = false\n        self._alwaysShowCroppingGrid    = false\n        self._translucencyAlwaysHidden  = false\n        self._gridOverlayHidden         = false\n        self._croppingViewsHidden       = false\n        \n        self.disableForgroundMatching   = false\n        \n        self.rotationContentOffset = .zero\n        self.rotationContentSize   = .zero\n        self.rotationBoundFrame    = .zero\n        self.originalCropBoxSize   = .zero\n        self.originalContentOffset = .zero\n        self.initialSetupPerformed = false\n        self.maximumZoomScale      = Constants.maximumZoomScale\n        self.applyInitialCroppedImageFrame = false\n        \n        self.dynamicBlurEffect = false\n        \n        self.restoreAngle           = 0\n        self.restoreImageCropFrame  = .zero\n        \n        super.init(frame: .zero)\n        \n        // UI manager\n        self.cropUIManager = CLDCropViewUIManager(cropView: self)\n        \n        // The pan controller to recognize gestures meant to resize the grid view\n        self.gridPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(gridPanGestureRecognized(_:)))\n        \n        self.cropBoxResizeEnabled     = true\n        self.alwaysShowCroppingGrid   = false\n        self.translucencyAlwaysHidden = false\n        \n        // View properties\n        self.autoresizingMask = [.flexibleHeight , .flexibleWidth]\n        self.backgroundColor  = UIColor(white: 0.12, alpha: 1.0)\n        self.cropBoxFrame = CGRect.zero\n        self._isEditing   = false\n        self._cropBoxResizeEnabled   = true\n        self._aspectRatio            = CGSize.zero\n        self.resetAspectRatioEnabled = true\n        self.cropAdjustingDelay = Constants.timerDuration\n        self.cropViewPadding    = Constants.padding\n        \n        \n        /* Dynamic animation blurring is only possible on iOS 9, however since the API was available on iOS 8,\n         we'll need to manually check the system version to ensure that it's available. */\n        self.dynamicBlurEffect = UIDevice.current.systemVersion.compare(\"9.0\", options: .numeric) != .orderedAscending\n        \n        // Scroll View\n        self.scrollViewDelegate = CLDCropScrollViewController(cropView: self)\n        \n        self.scrollView = CLDCropScrollView(frame: bounds)\n        self.scrollView.delegate = self.scrollViewDelegate\n        \n        self.addSubview(self.scrollView)\n        \n        // Disable smart inset behavior in iOS 11\n        if #available(iOS 11.0, *) {\n            self.scrollView.contentInsetAdjustmentBehavior = .never\n        }\n        \n        self.scrollView.touchesBegan = { [weak self] in self?.startEditing() }\n        self.scrollView.touchesEnded = { [weak self] in self?.startResetTimer() }\n        \n        // Background Image View\n        self.backgroundImageView = UIImageView(image: self.image)\n        self.backgroundImageView.layer.minificationFilter = CALayerContentsFilter.trilinear\n        \n        // Background container view\n        self.backgroundContainerView = UIView(frame: self.backgroundImageView.frame)\n        self.backgroundContainerView.addSubview(self.backgroundImageView)\n        self.scrollView.addSubview(self.backgroundContainerView)\n        \n        // Grey transparent overlay view\n        self.overlayView = UIView(frame: bounds)\n        self.overlayView.autoresizingMask = [.flexibleHeight , .flexibleWidth]\n        self.overlayView.backgroundColor  = self.backgroundColor?.withAlphaComponent(0.35)\n        self.overlayView.isHidden = false\n        self.overlayView.isUserInteractionEnabled = false\n        self.addSubview(self.overlayView)\n        \n        // Translucency View\n        self.translucencyEffect = UIBlurEffect(style: UIBlurEffect.Style.dark)\n        self.translucencyView   = UIVisualEffectView(effect: self.translucencyEffect)\n        self.translucencyView.frame     = self.bounds\n        self.translucencyView.isHidden  = self.translucencyAlwaysHidden\n        self.translucencyView.isUserInteractionEnabled = false\n        self.translucencyView.autoresizingMask = [.flexibleHeight , .flexibleWidth]\n        self.addSubview(self.translucencyView)\n        \n        // The forground container that holds the foreground image view\n        self.foregroundContainerView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))\n        self.foregroundContainerView.clipsToBounds = true\n        self.foregroundContainerView.isUserInteractionEnabled = false\n        self.addSubview(self.foregroundContainerView)\n        \n        self.foregroundImageView = UIImageView(image: self.image)\n        self.foregroundImageView.layer.minificationFilter = CALayerContentsFilter.trilinear\n        self.foregroundContainerView.addSubview(self.foregroundImageView)\n        \n        // Disable colour inversion for the image views\n        if #available(iOS 11.0, *) {\n            self.foregroundImageView.accessibilityIgnoresInvertColors = true\n            self.backgroundImageView.accessibilityIgnoresInvertColors = true\n        }\n        \n        // The white grid overlay view\n        self.gridOverlayView = CLDCropOverlayView(frame: self.foregroundContainerView.frame)\n        self.gridOverlayView.isUserInteractionEnabled = false\n        self.gridOverlayView.isGridHidden = true\n        self.addSubview(self.gridOverlayView)\n        \n        self.gridPanGestureRecognizer.delegate = self\n        self.scrollView.panGestureRecognizer.require(toFail: self.gridPanGestureRecognizer)\n        self.addGestureRecognizer(self.gridPanGestureRecognizer)\n    }\n    \n    public required init?(coder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    // MARK: - View Layout\n    \n    /**\n     Performs the initial set up, including laying out the image and applying any restore properties.\n     This should be called once the crop view has been added to a parent that is in its final layout frame.\n     */\n    public func performInitialSetup() {\n        \n        // Calling this more than once is potentially destructive\n        if initialSetupPerformed {\n            return\n        }\n        \n        // Disable from calling again\n        initialSetupPerformed = true\n        \n        // Perform the initial layout of the image\n        layoutInitialImage()\n        \n        // -- State Restoration --\n        \n        // If the angle value was previously set before this point, apply it now\n        if (restoreAngle != 0) {\n            angle = restoreAngle\n            restoreAngle = 0\n            cropBoxLastEditedAngle = angle\n        }\n        \n        // If an image crop frame was also specified before creation, apply it now\n        if !restoreImageCropFrame.isEmpty {\n            imageCropFrame = restoreImageCropFrame\n            restoreImageCropFrame = .zero\n        }\n        \n        // Save the current layout state for later\n        captureStateForImageRotation()\n        \n        // Check if we performed any resetabble modifications\n        checkForCanReset()\n    }\n    \n    private func layoutInitialImage() {\n        \n        let scaledImageSize = cropUIManager.manualLayout_initialImageAndGetScaledImageSize()\n            \n        // Save the current state for use with 90-degree rotations\n        cropBoxLastEditedAngle = 0\n        captureStateForImageRotation()\n        \n        //save the size for checking if we're in a resettable state\n        originalCropBoxSize   = resetAspectRatioEnabled ? scaledImageSize : cropBoxFrame.size\n        originalContentOffset = scrollView.contentOffset\n        \n        checkForCanReset()\n        matchForegroundToBackground()\n    }\n    \n    internal func matchForegroundToBackground() {\n        if disableForgroundMatching { return }\n        \n        // We can't simply match the frames since if the images are rotated, the frame property becomes unusable\n        if let view = backgroundContainerView.superview {\n            foregroundImageView.frame = view.convert(backgroundContainerView.frame, to: foregroundContainerView)\n        }\n    }\n    \n    private func updateCropBoxFrame(withGesture point: CGPoint) {\n        \n        cropBoxFrame = Calculator.CropBox.calculateFrame(given: point, in: self)\n        checkForCanReset()\n    }\n    \n    private func toggleTranslucencyViewVisible(_ visible: Bool) {\n        \n        if dynamicBlurEffect == false {\n            translucencyView.alpha  = visible ? 1.0 : 0.0\n        } else {\n            translucencyView.effect = visible ? translucencyEffect : nil\n        }\n    }\n    \n    // MARK: - Gesture Recognizer - ====================================================================================\n    \n    @objc private func gridPanGestureRecognized(_ recognizer: UIPanGestureRecognizer) {\n        \n        let point = recognizer.location(in: self)\n        \n        switch recognizer.state {\n        case .began:\n            startEditing()\n            panOriginPoint  = point\n            cropOriginFrame = cropBoxFrame\n            tappedEdge = Calculator.overlayEdge(for: panOriginPoint, cropBoxFrame: cropBoxFrame)\n            break\n        case .ended:\n            startResetTimer()\n            break\n        default:\n            break\n        }\n        updateCropBoxFrame(withGesture: point)\n    }\n    \n    // MARK: - Timer                ====================================================================================\n    \n    internal func startResetTimer() {\n        \n        if let _ = resetTimer {} else {\n            resetTimer = Timer.scheduledTimer(timeInterval: cropAdjustingDelay, target: self, selector: #selector(timerTriggered), userInfo: nil, repeats: false)\n        }\n    }\n    \n    @objc private func timerTriggered() {\n        \n        setEditing(false, resetCropBox: true, animated: true)\n        resetTimer?.invalidate()\n        resetTimer = nil\n    }\n    \n    internal func cancelResetTimer() {\n        \n        resetTimer?.invalidate()\n        resetTimer = nil\n    }\n    \n    // MARK: - =========================================================================================================\n    \n    /**\n     Changes the aspect ratio of the crop box to match the one specified\n     \n     - parameter aspectRatio The aspect ratio (For example 16:9 is 16.0f/9.0f). 'CGSizeZero' will reset it to the image's own ratio\n     - parameter animated Whether the locking effect is animated\n     */\n    public func setAspectRatio(_ newValue: CGSize, animated: Bool) {\n        \n        _aspectRatio = newValue\n        \n        let adjustments = Calculator.AspectRatio.postChangeAdjustments(given: newValue, animated: animated, in: self)\n        \n        cropBoxLastEditedSize  = adjustments.cropBoxFrame.size\n        cropBoxLastEditedAngle = angle\n        \n        let translateBlock : () -> Void = {\n\n            self.scrollView.contentOffset = adjustments.scrollOffset\n            self.cropBoxFrame = adjustments.cropBoxFrame\n            \n            if (adjustments.ShouldZoomOut) {\n                self.scrollView.zoomScale = self.scrollView.minimumZoomScale\n            }\n            self.moveCroppedContentToCenterAnimated(false)\n            self.checkForCanReset()\n        }\n        \n        switch animated {\n        case false:\n            translateBlock()\n            \n        case true :\n            UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0,\n                           initialSpringVelocity: 0.7, options: [.beginFromCurrentState],\n                           animations: translateBlock, completion: nil)\n        }\n    }\n    \n    public func lockAspectRatio(to aspectRatio: CGSize) {\n       \n        if aspectRatioLockEnabled {\n             _aspectRatio = aspectRatio\n        }\n    }\n    \n    /**\n     Rotates the entire canvas to a 90-degree angle. The default rotation is counterclockwise.\n     \n     - parameter animated Whether the transition is animated\n     */\n    public func rotateImageNinetyDegreesAnimated(_ animated: Bool) {\n        \n        rotateImageNinetyDegreesAnimated(animated, clockwise: false)\n    }\n    \n    /**\n     Rotates the entire canvas to a 90-degree angle\n     \n     - parameter animated Whether the transition is animated\n     - parameter clockwise Whether the rotation is clockwise. Passing 'NO' means counterclockwise\n     */\n    public func rotateImageNinetyDegreesAnimated(_ animated: Bool, clockwise: Bool) {\n        \n        cropUIManager.manualLayout_rotateImageNinetyDegreesAnimated(animated, clockwise: clockwise)\n    }\n    \n    /**\n     When triggered, the crop view will perform a relayout to ensure the crop box\n     fills the entire crop view region\n     */\n    public func moveCroppedContentToCenterAnimated(_ animated: Bool) {\n        cropUIManager.manualLayout_moveCroppedContentToCenterAnimated(animated)\n    }\n    \n    // MARK: -- Editing Mode\n    internal func captureStateForImageRotation() {\n        \n        cropBoxLastEditedSize         = cropBoxFrame.size\n        cropBoxLastEditedZoomScale    = scrollView.zoomScale\n        cropBoxLastEditedMinZoomScale = scrollView.minimumZoomScale\n    }\n    \n    // MARK: -- Resettable State\n    internal func checkForCanReset() {\n        \n        var resettable = false\n        \n        if angle != 0 { // Image has been rotated\n            resettable = true\n        }\n        else if scrollView.zoomScale > scrollView.minimumZoomScale + CGFloat.ulpOfOne { // Image has been zoomed in\n            resettable = true\n        }\n        else if\n            Int(floor(cropBoxFrame.width )) != Int(floor(originalCropBoxSize.width )) ||\n                Int(floor(cropBoxFrame.height)) != Int(floor(originalCropBoxSize.height)) // Crop box has been changed\n        {\n            resettable = true\n        }\n        else if\n            Int(floor(scrollView.contentOffset.x)) != Int(floor(originalContentOffset.x)) ||\n                Int(floor(scrollView.contentOffset.y)) != Int(floor(originalContentOffset.y))\n        {\n            resettable = true\n        }\n        \n        isResettable = resettable\n    }\n    \n    // MARK: -- fileprivate methods\n    fileprivate func applyCropFrameAdjutsments(to scrollView: UIScrollView, originPoint: CGPoint, minimumScale: CGFloat, adjustedZoom scale: CGFloat) {\n        \n        let scaledOffset   = CGPoint(x: originPoint.x * minimumScale,\n                                     y: originPoint.y * minimumScale)\n        \n        // Zoom into the scroll view to the appropriate size\n        scrollView.zoomScale = scrollView.minimumZoomScale * scale\n        \n        scrollView.contentOffset = CGPoint(x: (scaledOffset.x * scale) - scrollView.contentInset.left,\n                                           y: (scaledOffset.y * scale) - scrollView.contentInset.top)\n    }\n    \n    fileprivate func applyDidSetCropBoxFrame(to rectangle: CGRect) {\n        \n        // Set the clipping view to match the new rect\n        foregroundContainerView.frame = rectangle\n        \n        // Set the new overlay view to match the same region\n        gridOverlayView.frame = rectangle\n        \n        Calculator.CropBox.updateScrollView(scrollView, given: backgroundContainerView.bounds.size,\n                                            boundingRect: self.bounds, newCropBox: rectangle)\n        \n        // Re-align the background content to match\n        matchForegroundToBackground()\n    }\n}\n// MARK: - UIGestureRecognizerDelegate\nextension CLDCropView : UIGestureRecognizerDelegate {\n    \n    public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {\n        \n        if gestureRecognizer != gridPanGestureRecognizer {\n            return true\n        }\n        \n        let tapPoint = gestureRecognizer.location(in: self)\n        \n        let rectangle = gridOverlayView.frame\n        let innerRectangle = rectangle.insetBy(dx:  22.0, dy:  22.0)\n        let outerRectangle = rectangle.insetBy(dx: -22.0, dy: -22.0)\n        \n        if innerRectangle.contains(tapPoint) || !outerRectangle.contains(tapPoint) {\n            return false\n        }\n        \n        return true\n    }\n    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {\n        \n        if gridPanGestureRecognizer.state == .changed {\n            return false\n        }\n        return true\n    }\n}\n\n// MARK: - General extensions\nfileprivate extension CGRect {\n    \n    var isValidBoxSize : Bool {\n        // Upon init, sometimes the box size is still 0 (or NaN), which can result in CALayer issues\n        let threashold = CGFloat.ulpOfOne\n        if (width < threashold || height < threashold) { return false }\n        if (width.isNaN        || height.isNaN       ) { return false }\n        return true\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/CropView/CLDCropViewCalculator.swift",
    "content": "//\n//  CLDCropViewCalculator.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\nimport Foundation\nimport CoreGraphics\n\nfileprivate extension CGSize {\n    \n    var floored : CGSize {\n        \n        return CGSize(width : floor(width ),\n                      height: floor(height))\n    }\n}\ninternal extension CLDCropView.Calculator {\n    \n    static func bounds(for viewBounds: CGRect, padding: CGFloat, cropRegion insets: UIEdgeInsets) -> CGRect {\n        \n        var rectangle = CGRect.zero\n        rectangle.origin.x = padding + insets.left\n        rectangle.origin.y = padding + insets.top\n        rectangle.size.width  = viewBounds.width  - ((padding * 2) + insets.left + insets.right)\n        rectangle.size.height = viewBounds.height - ((padding * 2) + insets.top  + insets.bottom)\n        return rectangle\n    }\n    static func overlayEdge(for point: CGPoint, cropBoxFrame: CGRect) -> CLDCropViewOverlayEdge {\n        \n        let     threashold = CGFloat(64)\n        let halfThreashold = threashold / 2.0\n        \n        var rectangle = cropBoxFrame\n        \n        // Account for padding around the box\n        rectangle = rectangle.insetBy(dx: -halfThreashold, dy: -halfThreashold)\n        \n        // Make sure the corners take priority\n        let rectangleTopLeft = CGRect(origin: rectangle.origin, size: CGSize(width: threashold, height: threashold))\n        if  rectangleTopLeft.contains(point) {\n            return CLDCropViewOverlayEdge.topLeft\n        }\n        \n        var rectangleTopRight = rectangleTopLeft\n        rectangleTopRight.origin.x = rectangle.maxX - threashold\n        if  rectangleTopRight.contains(point) {\n            return CLDCropViewOverlayEdge.topRight\n        }\n        \n        var rectangleBottomLeft = rectangleTopLeft\n        rectangleBottomLeft.origin.y = rectangle.maxY - threashold\n        if  rectangleBottomLeft.contains(point) {\n            return CLDCropViewOverlayEdge.bottomLeft\n        }\n        \n        var rectangleBottomRight = rectangleTopRight\n        rectangleBottomRight.origin.y = rectangleBottomLeft.origin.y\n        if  rectangleBottomRight.contains(point) {\n            return CLDCropViewOverlayEdge.bottomRight\n        }\n        \n        // Check for edges\n        let topRect = CGRect(origin: rectangle.origin, size: CGSize(width: rectangle.width, height: threashold))\n        if  topRect.contains(point) {\n            return CLDCropViewOverlayEdge.top\n        }\n        \n        var bottomRect = topRect\n        bottomRect.origin.y = rectangle.maxY - threashold\n        if  bottomRect.contains(point) {\n            return CLDCropViewOverlayEdge.bottom\n        }\n        \n        let leftRect = CGRect(origin: rectangle.origin, size: CGSize(width: threashold, height: rectangle.height))\n        if  leftRect.contains(point) {\n            return CLDCropViewOverlayEdge.left\n        }\n        \n        var rightRect = leftRect\n        rightRect.origin.x = rectangle.maxX - threashold\n        if  rightRect.contains(point) {\n            return CLDCropViewOverlayEdge.right\n        }\n        \n        return CLDCropViewOverlayEdge.none\n    }\n}\ninternal extension CLDCropView.Calculator.ImageCrop   {\n    /**\n     In relation to the coordinate space of the image, the frame that the crop view is focusing on\n     */\n    static func computeFrame(given imageSize: CGSize, scrollView: UIScrollView, cropBox: CGRect) -> CGRect {\n        \n        let  targetSize = imageSize\n        let contentSize = scrollView.contentSize\n        \n        let cropRectangle = cropBox\n        \n        let offset = scrollView.contentOffset\n        let insets = scrollView.contentInset\n        \n        let scale = min(targetSize.width / contentSize.width, targetSize.height / contentSize.height)\n        \n        var rectangle = CGRect.zero\n        \n        // Calculate the normalized origin\n        rectangle.origin.x = floor( (floor(offset.x) + insets.left) * (targetSize.width  / contentSize.width ) )\n        rectangle.origin.x = max(0, rectangle.origin.x)\n        \n        rectangle.origin.y = floor( (floor(offset.y) + insets.top ) * (targetSize.height / contentSize.height) )\n        rectangle.origin.y = max(0, rectangle.origin.y)\n        \n        // Calculate the normalized width\n        rectangle.size.width = ceil(cropRectangle.width * scale)\n        rectangle.size.width = min(targetSize.width, rectangle.width)\n        \n        // Calculate normalized height\n        if floor(cropRectangle.width) == floor(cropRectangle.height) {\n            rectangle.size.height = rectangle.size.width\n        } else {\n            rectangle.size.height = ceil(cropRectangle.height * scale)\n            rectangle.size.height = min(targetSize.height, rectangle.size.height)\n        }\n        rectangle.size.height = min(targetSize.height, rectangle.size.height)\n        \n        return rectangle\n    }\n    \n    static func computeAdjutsments(for cropView: CLDCropView, scrollView: UIScrollView, content contentBounds: CGRect, newValue: CGRect) -> (cropFrame:CGRect, minimumZoomScale: CGFloat, adjustedZoomScale: CGFloat) {\n        \n        // Convert the image crop frame's size from image space to the screen space\n        let minimumScale    = scrollView.minimumZoomScale\n        let scaledCropSize = CGSize(width : newValue.width  * minimumScale,\n                                    height: newValue.height * minimumScale)\n        \n        // Work out the scale necessary to upscale the crop size to fit the content bounds of the crop bound\n        let boundsRectangle  = contentBounds\n        \n        let scale = min(boundsRectangle.width  / scaledCropSize.width,\n                        boundsRectangle.height / scaledCropSize.height)\n        \n        // Work out the size and offset of the upscaled crop box\n        var frameRectangle = CGRect.zero\n        frameRectangle.size = CGSize(width : scaledCropSize.width  * scale,\n                                     height: scaledCropSize.height * scale)\n        \n        //set the crop box\n        var cropBoxRectangle = CGRect.zero\n        cropBoxRectangle.size = frameRectangle.size\n        cropBoxRectangle.origin.x = boundsRectangle.midX - (frameRectangle.width  * 0.5)\n        cropBoxRectangle.origin.y = boundsRectangle.midY - (frameRectangle.height * 0.5)\n        \n        return (cropFrame: cropBoxRectangle, minimumZoomScale: minimumScale, adjustedZoomScale: scale)\n    }\n}\ninternal extension CLDCropView.Calculator.CropBox     {\n    \n    /**\n     Clamp the cropping region to the inset boundaries of the screen\n     */\n    static func clampFrame(given rectangle: CGRect, cropBox: CGRect, minimumBoxSize: CGFloat) -> CGRect {\n        \n        func clampValueToRange(input value: CGFloat, maximumValue: CGFloat, minimumValue: CGFloat) -> CGFloat {\n        \n            var temp = value\n            temp = floor( min(temp, maximumValue) )\n            temp = ceil ( max(temp, minimumValue) )\n            return temp\n        }\n        func clampedValues(contentOrigin: CGFloat, clampedOrigin: CGFloat, side: CGFloat) -> (origin:CGFloat, side: CGFloat) {\n            \n            var internalVariable      = side\n            let internalClampedOrigin = floor( max(clampedOrigin, ceil(contentOrigin)) )\n            \n            // If we clamp the value, ensure we compensate for the subsequent delta\n            // generated in the width (Or else, the box will keep growing)\n            let delta  = clampedOrigin - ceil(contentOrigin)\n            if (delta < -CGFloat.ulpOfOne) {\n                internalVariable += delta\n            }\n            return (internalClampedOrigin,internalVariable)\n        }\n        \n        let xValues = clampedValues(contentOrigin: rectangle.origin.x, clampedOrigin: cropBox.origin.x, side: cropBox.width)\n        let yValues = clampedValues(contentOrigin: rectangle.origin.y, clampedOrigin: cropBox.origin.y, side: cropBox.height)\n        \n        // Given the clamped X values, make sure we can't extend the crop box beyond the edge of the screen in the current state\n        // Make sure we can't make the crop box too small\n        let maxWidth  = (rectangle.origin.x + rectangle.width) - xValues.origin\n        let clampedWidth = clampValueToRange(input: xValues.side, maximumValue: maxWidth, minimumValue: minimumBoxSize)\n        \n        // Given the clamped Y values, make sure we can't extend the crop box beyond the edge of the screen in the current state\n        // Make sure we can't make the crop box too small\n        let maxHeight = (rectangle.origin.y + rectangle.height) - yValues.origin\n        let clampedHeight = clampValueToRange(input: yValues.side, maximumValue: maxHeight, minimumValue: minimumBoxSize)\n        \n        return CGRect(x: xValues.origin, y: yValues.origin, width: clampedWidth, height: clampedHeight)\n    }\n    \n    static func updateScrollView(_ scrollView: UIScrollView, given imageSize : CGSize, boundingRect: CGRect, newCropBox cropBox: CGRect) {\n        \n        // if necessary, work out the new minimum size of the scroll view so it fills the crop box\n        let scale = max(cropBox.height / imageSize.height,\n                        cropBox.width  / imageSize.width)\n        \n        // Reset the scroll view insets to match the region of the new crop rect\n        scrollView.contentInset = UIEdgeInsets(top : cropBox.minY,\n                                               left: cropBox.minX,\n                                               bottom: boundingRect.maxY - cropBox.maxY,\n                                               right : boundingRect.maxX - cropBox.maxX)\n        \n        scrollView.minimumZoomScale = scale\n        \n        // Make sure content isn't smaller than the crop box\n        scrollView.contentSize = scrollView.contentSize.floored\n        \n        // IMPORTANT: Force the scroll view to update its content after changing the zoom scale\n        let zoomScale = scrollView.zoomScale\n        scrollView.zoomScale = zoomScale\n    }\n    \n    /**\n     Calculates the new crop box frame by the users gesture\n     */\n    static func calculateFrame(given gesturePoint: CGPoint, in cropView: CLDCropView) -> CGRect {\n        \n        var    rectangle = cropView.cropBoxFrame\n        let  originFrame = cropView.cropOriginFrame\n        let contentFrame = cropView.contentBounds\n        \n        var point = gesturePoint\n        point.x = max(contentFrame.origin.x - cropView.cropViewPadding, point.x)\n        point.y = max(contentFrame.origin.y - cropView.cropViewPadding, point.y)\n        \n        // The delta between where we first tapped, and where our finger is now\n        var xDelta = ceil(point.x - cropView.panOriginPoint.x)\n        var yDelta = ceil(point.y - cropView.panOriginPoint.y)\n        \n        // Current aspect ratio of the crop box in case we need to clamp it\n        let aspectRatio = (originFrame.width / originFrame.height)\n        \n        // Note whether we're being aspect transformed horizontally or vertically\n        var aspectHorizontal = false\n        var aspectVertical   = false\n        \n        // Depending on which corner we drag from, set the appropriate min flag to\n        // ensure we can properly clamp the XY value of the box if it overruns the minimum size\n        // (Otherwise the image itself will slide with the drag gesture)\n        var clampMinFromTop  = false\n        var clampMinFromLeft = false\n        \n        switch cropView.tappedEdge {\n        case .left:\n            \n            if cropView.aspectRatioLockEnabled {\n                aspectHorizontal = true\n                xDelta = max(xDelta, 0)\n                \n                let scaleOrigin = CGPoint(x: originFrame.maxX, y: originFrame.midY)\n                rectangle.size.height = rectangle.width / aspectRatio\n                rectangle.origin.y    = scaleOrigin.y - (rectangle.height * 0.5)\n            }\n            \n            let newWidth  = originFrame.width - xDelta\n            let newHeight = originFrame.height\n            \n            if min(newHeight, newWidth) / max(newHeight, newWidth) >= cropView.minimumAspectRatio {\n                rectangle.origin.x   = originFrame.origin.x + xDelta\n                rectangle.size.width = originFrame.width - xDelta\n            }\n            clampMinFromLeft = true\n            \n        case .right:\n            \n            if cropView.aspectRatioLockEnabled {\n                aspectHorizontal = true\n                \n                let scaleOrigin = CGPoint(x: originFrame.minX, y: originFrame.midY)\n                rectangle.size.height = rectangle.width / aspectRatio\n                rectangle.origin.y    = scaleOrigin.y - (rectangle.height * 0.5)\n                rectangle.size.width  = originFrame.size.width + xDelta\n                rectangle.size.width  = min(rectangle.width, contentFrame.height * aspectRatio)\n                \n            } else {\n                \n                let newWidth  = originFrame.width + xDelta\n                let newHeight = originFrame.height\n                \n                if min(newHeight, newWidth) / max(newHeight, newWidth) >= cropView.minimumAspectRatio {\n                    rectangle.size.width = originFrame.width + xDelta\n                }\n            }\n            \n        case .bottom:\n            \n            if cropView.aspectRatioLockEnabled {\n                \n                aspectVertical = true\n                \n                let scaleOrigin = CGPoint(x: originFrame.midX, y: originFrame.minY)\n                rectangle.size.width  = rectangle.height * aspectRatio\n                rectangle.origin.x    = scaleOrigin.x - (rectangle.size.width * 0.5)\n                rectangle.size.height = originFrame.height + yDelta\n                rectangle.size.height = min(rectangle.height, contentFrame.width / aspectRatio)\n                \n            } else {\n                \n                let newWidth  = originFrame.width\n                let newHeight = originFrame.height + yDelta\n                \n                if min(newHeight, newWidth) / max(newHeight, newWidth) >= cropView.minimumAspectRatio {\n                    rectangle.size.height = originFrame.height + yDelta\n                }\n            }\n            \n        case .top:\n            \n            if cropView.aspectRatioLockEnabled {\n                aspectVertical = true\n                yDelta = max(0,yDelta)\n                \n                let scaleOrigin = CGPoint(x: originFrame.midX, y: originFrame.midY)\n                rectangle.origin.x    = scaleOrigin.x - (rectangle.size.width * 0.5)\n                rectangle.origin.y    = originFrame.origin.y + yDelta\n                rectangle.size.width  = rectangle.height * aspectRatio\n                rectangle.size.height = originFrame.height - yDelta\n                \n            } else {\n                \n                let  newWidth = originFrame.width\n                let newHeight = originFrame.height - yDelta\n                \n                if min(newHeight, newWidth) / max(newHeight, newWidth) >= cropView.minimumAspectRatio {\n                    rectangle.origin.y    = originFrame.origin.y + yDelta\n                    rectangle.size.height = originFrame.height   - yDelta\n                }\n            }\n            \n            clampMinFromTop = true\n            \n        case .topLeft:\n            \n            if cropView.aspectRatioLockEnabled {\n                xDelta = max(xDelta, 0)\n                yDelta = max(yDelta, 0)\n                \n                var distance = CGPoint.zero\n                distance.x = 1.0 - (xDelta / originFrame.width )\n                distance.y = 1.0 - (yDelta / originFrame.height)\n                \n                let scale = (distance.x + distance.y) * 0.5\n                \n                rectangle.size.width  = ceil(originFrame.width  * scale)\n                rectangle.size.height = ceil(originFrame.height * scale)\n                rectangle.origin.x = originFrame.origin.x + (originFrame.width  - rectangle.width )\n                rectangle.origin.y = originFrame.origin.y + (originFrame.height - rectangle.height)\n                \n                aspectHorizontal = true\n                aspectVertical   = true\n                \n            } else {\n                \n                let newWidth  = originFrame.width  - xDelta\n                let newHeight = originFrame.height - yDelta\n                \n                if min(newHeight, newWidth) / max(newHeight, newWidth) >= cropView.minimumAspectRatio {\n                    rectangle.origin.x    = originFrame.origin.x + xDelta\n                    rectangle.origin.y    = originFrame.origin.y + yDelta\n                    rectangle.size.width  = originFrame.width    - xDelta\n                    rectangle.size.height = originFrame.height   - yDelta\n                }\n            }\n            clampMinFromTop  = true\n            clampMinFromLeft = true\n            \n        case .topRight:\n            \n            if cropView.aspectRatioLockEnabled {\n                \n                xDelta = min(xDelta, 0)\n                yDelta = max(yDelta, 0)\n                \n                var distance = CGPoint.zero\n                distance.x = 1.0 - ((-xDelta) / originFrame.width )\n                distance.y = 1.0 - (( yDelta) / originFrame.height)\n                \n                let scale = (distance.x + distance.y) * 0.5\n                \n                rectangle.size.width  = ceil(originFrame.width  * scale)\n                rectangle.size.height = ceil(originFrame.height * scale)\n                rectangle.origin.y    = originFrame.origin.y + (originFrame.height - rectangle.height)\n                \n                aspectHorizontal = true\n                aspectVertical   = true\n                \n            } else {\n                \n                let newWidth  = originFrame.width  + xDelta\n                let newHeight = originFrame.height - yDelta\n                \n                if min(newHeight, newWidth) / max(newHeight, newWidth) >= cropView.minimumAspectRatio {\n                    rectangle.size.width  = originFrame.width    + xDelta\n                    rectangle.size.height = originFrame.height   - yDelta\n                    rectangle.origin.y    = originFrame.origin.y + yDelta\n                }\n            }\n            clampMinFromTop = true\n            \n        case .bottomLeft:\n            \n            if cropView.aspectRatioLockEnabled {\n                \n                var distance = CGPoint.zero\n                distance.x = 1.0 - ( xDelta / originFrame.width )\n                distance.y = 1.0 - (-yDelta / originFrame.height)\n                \n                let scale = (distance.x + distance.y) * 0.5\n                rectangle.size.width  = ceil(originFrame.width  * scale)\n                rectangle.size.height = ceil(originFrame.height * scale)\n                rectangle.origin.x  = originFrame.maxX - rectangle.width\n                \n                aspectHorizontal = true\n                aspectVertical   = true\n                \n            } else {\n                \n                let newWidth  = originFrame.width  - xDelta\n                let newHeight = originFrame.height + yDelta\n                \n                if min(newHeight, newWidth) / max(newHeight, newWidth) >= cropView.minimumAspectRatio {\n                    rectangle.origin.x    = originFrame.origin.x + xDelta\n                    rectangle.size.height = originFrame.height   + yDelta\n                    rectangle.size.width  = originFrame.width    - xDelta\n                }\n            }\n            clampMinFromLeft = true\n            \n            \n        case .bottomRight:\n            \n            if cropView.aspectRatioLockEnabled {\n                \n                var distance = CGPoint.zero\n                distance.x = 1.0 - ((-1 * xDelta) / originFrame.width )\n                distance.y = 1.0 - ((-1 * yDelta) / originFrame.height)\n                \n                let scale = (distance.x + distance.y) * 0.5\n                rectangle.size.width  = ceil(originFrame.width  * scale)\n                rectangle.size.height = ceil(originFrame.height * scale)\n                \n                aspectHorizontal = true\n                aspectVertical   = true\n                \n            } else {\n                \n                let newWidth  = originFrame.width  + xDelta\n                let newHeight = originFrame.height + yDelta\n                \n                if min(newHeight, newWidth) / max(newHeight, newWidth) >= cropView.minimumAspectRatio {\n                    rectangle.size.height = originFrame.height + yDelta\n                    rectangle.size.width  = originFrame.width  + xDelta\n                }\n            }\n            \n        case .none:\n            break\n        }\n        \n        //The absolute max/min size the box may be in the bounds of the crop view\n        \n        var minSize = CGSize(width: CLDCropView.Constants.minimumBoxSize, height: CLDCropView.Constants.minimumBoxSize)\n        var maxSize = CGSize(width: contentFrame.width                  , height: contentFrame.height                 )\n        \n        //clamp the box to ensure it doesn't go beyond the bounds we've set\n        if (cropView.aspectRatioLockEnabled && aspectHorizontal) {\n            minSize.width  = CLDCropView.Constants.minimumBoxSize * aspectRatio\n            maxSize.height = contentFrame.width / aspectRatio\n        }\n        \n        if (cropView.aspectRatioLockEnabled && aspectVertical) {\n            maxSize.width  = contentFrame.height * aspectRatio\n            minSize.height = CLDCropView.Constants.minimumBoxSize / aspectRatio\n        }\n        \n        // Clamp the width if it goes over\n        if (clampMinFromLeft) {\n            let maxWidth  = cropView.cropOriginFrame.maxX - contentFrame.origin.x\n            rectangle.size.width = min(rectangle.width, maxWidth)\n        }\n        \n        if (clampMinFromTop) {\n            let maxHeight = cropView.cropOriginFrame.maxY - contentFrame.origin.y\n            rectangle.size.height = min(rectangle.height, maxHeight)\n        }\n        \n        // Clamp the minimum size\n        rectangle.size.width  = max(rectangle.width , minSize.width )\n        rectangle.size.height = max(rectangle.height, minSize.height)\n        \n        // Clamp the maximum size\n        rectangle.size.width  = min(rectangle.width , maxSize.width )\n        rectangle.size.height = min(rectangle.height, maxSize.height)\n        \n        //Clamp the X position of the box to the interior of the cropping bounds\n        rectangle.origin.x = max(rectangle.origin.x, contentFrame.minX)\n        rectangle.origin.x = min(rectangle.origin.x, contentFrame.maxX - minSize.width)\n        \n        //Clamp the Y postion of the box to the interior of the cropping bounds\n        rectangle.origin.y = max(rectangle.origin.y, contentFrame.minY)\n        rectangle.origin.y = min(rectangle.origin.y, contentFrame.maxY - minSize.height)\n        \n        //Once the box is completely shrunk, clamp its ability to move\n        if (clampMinFromLeft && rectangle.width <= minSize.width + CGFloat.ulpOfOne) {\n            rectangle.origin.x = originFrame.maxX - minSize.width\n        }\n        \n        //Once the box is completely shrunk, clamp its ability to move\n        if (clampMinFromTop && rectangle.height <= minSize.height + CGFloat.ulpOfOne) {\n            rectangle.origin.y = originFrame.maxY - minSize.height\n        }\n        \n        return rectangle\n    }\n}\ninternal extension CLDCropView.Calculator.AspectRatio {\n    static func postChangeAdjustments(given newValue: CGSize, animated: Bool, in cropView: CLDCropView) -> (scrollOffset: CGPoint, cropBoxFrame: CGRect , ShouldZoomOut: Bool){\n        \n        var newAspectRatio = newValue\n        \n        // Passing in an empty size will revert back to the image aspect ratio\n        if (newAspectRatio.width < CGFloat.ulpOfOne && newAspectRatio.height < CGFloat.ulpOfOne ) {\n            newAspectRatio = CGSize(width: cropView.imageSize.width, height: cropView.imageSize.height)\n        }\n        \n        let  boundsFrame = cropView.contentBounds\n        var rectangle = cropView.cropBoxFrame\n        var offset = cropView.scrollView.contentOffset\n        \n        var cropBoxIsPortrait = false\n        if (Int(newAspectRatio.width) == 1 && Int(newAspectRatio.height) == 1) {\n            cropBoxIsPortrait = cropView.image.size.width > cropView.image.size.height\n        } else {\n            cropBoxIsPortrait = newAspectRatio.width < newAspectRatio.height\n        }\n        \n        var shouldZoomOut = false\n        switch cropBoxIsPortrait {\n        case true :\n            \n            let newWidth = floor(rectangle.height * (newAspectRatio.width / newAspectRatio.height) )\n            var delta = rectangle.width  - newWidth\n            rectangle.size.width  = newWidth\n            offset.x += (delta * 0.5)\n            \n            // Set to 0 to avoid accidental clamping by the crop frame sanitizer\n            if (delta < CGFloat.ulpOfOne ) {\n                rectangle.origin.x = boundsFrame.origin.x\n            }\n            \n            // If the aspect ratio causes the new width to extend\n            // beyond the content width, we'll need to zoom the image out\n            let boundsWidth = boundsFrame.width\n            if (newWidth > boundsWidth) {\n                let scale = boundsWidth / newWidth\n                \n                // Scale the new height\n                let newHeight = rectangle.height * scale\n                delta = rectangle.height - newHeight\n                rectangle.size.height = newHeight\n                \n                // Offset the Y position so it stays in the middle\n                offset.y += (delta * 0.5)\n                \n                // Clamp the width to the bounds width\n                rectangle.size.width = boundsWidth\n                shouldZoomOut = true\n            }\n            \n        case false:\n            let newHeight = floor(rectangle.width * (newAspectRatio.height/newAspectRatio.width) )\n            var delta = rectangle.height - newHeight\n            rectangle.size.height = newHeight\n            offset.y += (delta * 0.5)\n            \n            if delta < CGFloat.ulpOfOne {\n                rectangle.origin.y = boundsFrame.origin.y\n            }\n            \n            // If the aspect ratio causes the new height to extend\n            // beyond the content width, we'll need to zoom the image out\n            let boundsHeight = boundsFrame.height\n            if (newHeight > boundsHeight) {\n                let scale = boundsHeight / newHeight\n                \n                // Scale the new width\n                let newWidth = rectangle.width * scale\n                delta = rectangle.size.width - newWidth\n                rectangle.size.width = newWidth\n                \n                // Offset the Y position so it stays in the middle\n                offset.x += (delta * 0.5)\n                \n                // Clamp the width to the bounds height\n                rectangle.size.height = boundsHeight\n                shouldZoomOut = true\n            }\n        }\n        \n        return (scrollOffset: offset, cropBoxFrame: rectangle , ShouldZoomOut: shouldZoomOut)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/CropView/CLDCropViewUIManager.swift",
    "content": "//\n//  CLDCropViewUIManager.swift\n//  Cloudinary\n//\n//  Created by Oz Deutsch on 04/10/2020.\n//\n\nimport UIKit\n\ninternal class CLDCropViewUIManager {\n    \n    internal weak var cropView: CLDCropView!\n    \n    internal init(cropView: CLDCropView) {\n        \n        self.cropView = cropView\n    }\n    \n    /**\n    layout the initial image and returns the scaled image size\n    */\n    internal func manualLayout_initialImageAndGetScaledImageSize() -> CGSize {\n        \n        cropView.scrollView.contentSize = cropView.imageSize\n        \n        let boundsRectangle = cropView.contentBounds\n        let boundsSize      = boundsRectangle.size\n        \n        // Work out the minimum scale of the object\n        var scale = CGFloat(0.0)\n        \n        // Work out the size of the image to fit into the content bounds\n        scale = min(boundsRectangle.width / cropView.imageSize.width, boundsRectangle.height / cropView.imageSize.height)\n        \n        let scaledImageSize = CGSize(width : floor(cropView.imageSize.width  * scale),\n                                     height: floor(cropView.imageSize.height * scale))\n        \n        // If an aspect ratio was pre-applied to the crop view, use that to work out the minimum scale the image needs to be to fit\n        var cropBoxSize = CGSize.zero\n        \n        if (cropView.hasAspectRatio) {\n            \n            let    ratioScale = cropView.aspectRatio.width / cropView.aspectRatio.height // Work out the size of the width in relation to height\n            let fullSizeRatio = CGSize(width: boundsSize.height * ratioScale, height: boundsSize.height)\n            \n            let fitScale = min(boundsSize.width / fullSizeRatio.width, boundsSize.height / fullSizeRatio.height)\n            \n            cropBoxSize  = CGSize(width: fullSizeRatio.width * fitScale, height: fullSizeRatio.height * fitScale)\n            scale        = max(cropBoxSize.width / cropView.imageSize.width, cropBoxSize.height / cropView.imageSize.height)\n        }\n        \n        //Whether aspect ratio, or original, the final image size we'll base the rest of the calculations off\n        let scaledSize = CGSize(width: floor(cropView.imageSize.width * scale), height: floor(cropView.imageSize.height * scale))\n        \n        // Configure the scroll view\n        cropView.scrollView.minimumZoomScale = scale\n        cropView.scrollView.maximumZoomScale = scale * cropView.maximumZoomScale\n        \n        // Set the crop box to the size we calculated and align in the middle of the screen\n        var rectangle  = CGRect.zero\n        rectangle.size = cropView.hasAspectRatio ? cropBoxSize : scaledSize\n        rectangle.origin.x = boundsRectangle.origin.x + floor((boundsRectangle.width  - rectangle.width ) * 0.5)\n        rectangle.origin.y = boundsRectangle.origin.y + floor((boundsRectangle.height - rectangle.height) * 0.5)\n        cropView.cropBoxFrame = rectangle\n        \n        // Set the fully zoomed out state initially\n        cropView.scrollView.zoomScale   = cropView.scrollView.minimumZoomScale\n        cropView.scrollView.contentSize = scaledSize\n        \n        // If we ended up with a smaller crop box than the content, line up the content so its center\n        // is in the center of the cropbox\n        if (rectangle.width < scaledSize.width - CGFloat.ulpOfOne || rectangle.height < scaledSize.height - CGFloat.ulpOfOne) {\n            \n            var offset = CGPoint.zero\n            offset.x = -floor(boundsRectangle.midX - (scaledSize.width  * 0.5))\n            offset.y = -floor(boundsRectangle.midY - (scaledSize.height * 0.5))\n            cropView.scrollView.contentOffset = offset\n        }\n        \n        return scaledImageSize\n    }\n    \n    internal func manualLayout_moveCroppedContentToCenterAnimated(_ animated: Bool) {\n        \n        if cropView.internalLayoutDisabled { return }\n        \n        let contentRect  = cropView.contentBounds\n        var    cropFrame = cropView.cropBoxFrame\n        \n        // Ensure we only proceed after the crop frame has been setup for the first time\n        if (cropFrame.width < CGFloat.ulpOfOne || cropFrame.height < CGFloat.ulpOfOne) {\n            return\n        }\n        \n        // The scale we need to scale up the crop box to fit full screen\n        let scale = min(contentRect.width / cropFrame.width, contentRect.height / cropFrame.height)\n        \n        let focusPoint = CGPoint(x:   cropFrame.midX, y:   cropFrame.midY)\n        let   midPoint = CGPoint(x: contentRect.midX, y: contentRect.midY)\n        \n        cropFrame.size.width  = ceil(cropFrame.width  * scale)\n        cropFrame.size.height = ceil(cropFrame.height * scale)\n        \n        cropFrame.origin.x = contentRect.origin.x + ceil(0.5 * (contentRect.width  - cropFrame.width ))\n        cropFrame.origin.y = contentRect.origin.y + ceil(0.5 * (contentRect.height - cropFrame.height))\n        \n        // Work out the point on the scroll content that the focusPoint is aiming at\n        var contentTargetPoint = CGPoint.zero\n        contentTargetPoint.x = ((focusPoint.x + cropView.scrollView.contentOffset.x) * scale)\n        contentTargetPoint.y = ((focusPoint.y + cropView.scrollView.contentOffset.y) * scale)\n        \n        // Work out where the crop box is focusing, so we can re-align to center that point\n        var offset = CGPoint.zero\n        offset.x = -midPoint.x + contentTargetPoint.x\n        offset.y = -midPoint.y + contentTargetPoint.y\n        \n        // Clamp the content so it doesn't create any seams around the grid\n        offset.x = max(-cropFrame.origin.x, offset.x)\n        offset.y = max(-cropFrame.origin.y, offset.y)\n        \n        let translateBlock : () -> Void = {\n            \n            var offsetHelper = offset\n            \n            // Setting these scroll view properties will trigger\n            // the foreground matching method via their delegates,\n            // multiple times inside the same animation block, resulting\n            // in glitchy animations.\n            //\n            // Disable matching for now, and explicitly update at the end.\n            \n            self.cropView.disableForgroundMatching = true\n            \n            // Slight hack. This method needs to be called during `[UIViewController viewDidLayoutSubviews]`\n            // in order for the crop view to resize itself during iPad split screen events.\n            // On the first run, even though scale is exactly 1.0f, performing this multiplication introduces\n            // a floating point noise that zooms the image in by about 5 pixels. This fixes that issue.\n            if scale < 1.0 - CGFloat.ulpOfOne || scale > 1.0 + CGFloat.ulpOfOne {\n                \n                self.cropView.scrollView.zoomScale *= scale\n                self.cropView.scrollView.zoomScale = min(self.cropView.scrollView.maximumZoomScale, self.cropView.scrollView.zoomScale)\n            }\n            \n            // If it turns out the zoom operation would have exceeded the minizum zoom scale, don't apply\n            // the content offset\n            if (self.cropView.scrollView.zoomScale < self.cropView.scrollView.maximumZoomScale - CGFloat.ulpOfOne) {\n                \n                offsetHelper.x = min(-cropFrame.maxX + self.cropView.scrollView.contentSize.width , offset.x)\n                offsetHelper.y = min(-cropFrame.maxY + self.cropView.scrollView.contentSize.height, offset.y)\n                self.cropView.scrollView.contentOffset = offsetHelper\n            }\n            \n            self.cropView.cropBoxFrame = cropFrame\n            \n            self.cropView.disableForgroundMatching = false\n            \n            // Explicitly update the matching at the end of the calculations\n            self.cropView.matchForegroundToBackground()\n        }\n        \n        switch animated {\n        case false:\n            translateBlock()\n            \n        case true:\n            cropView.matchForegroundToBackground()\n            \n            DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {\n                \n                UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: [.beginFromCurrentState], animations: translateBlock, completion: nil)\n            }\n        }\n    }\n    \n    internal func manualLayout_rotateImageNinetyDegreesAnimated(_ animated: Bool, clockwise: Bool) {\n        \n        // Only allow one rotation animation at a time\n        if cropView.rotateAnimationInProgress { return }\n        \n        // Cancel any pending resizing timers\n        if cropView.resetTimer != nil {\n            \n            cropView.cancelResetTimer()\n            cropView.setEditing(false, resetCropBox: true, animated: false)\n            \n            cropView.cropBoxLastEditedAngle = cropView.angle\n            cropView.captureStateForImageRotation()\n        }\n        \n        // Work out the new angle, and wrap around once we exceed 360s\n        var newAngle = cropView.angle\n        newAngle = clockwise ? newAngle + 90 : newAngle - 90\n        \n        if (newAngle <= -360 || newAngle >= 360) {\n            newAngle = 0\n        }\n        \n        cropView._angle = newAngle\n        \n        // Convert the new angle to radians\n        var angleInRadians = CGFloat(0.0)\n        switch (newAngle) {\n        case   90: angleInRadians =  CGFloat(Double.pi / 2)\n        case  -90: angleInRadians = -CGFloat(Double.pi / 2)\n        case  180: angleInRadians =  CGFloat(Double.pi)\n        case -180: angleInRadians = -CGFloat(Double.pi)\n        case  270: angleInRadians =  CGFloat(Double.pi + (Double.pi / 2))\n        case -270: angleInRadians = -CGFloat(Double.pi + (Double.pi / 2))\n        default: break\n        }\n        \n        // Set up the transformation matrix for the rotation\n        let rotation = CGAffineTransform.identity.rotated(by: angleInRadians)\n        \n        // Work out how much we'll need to scale everything to fit to the new rotation\n        let contentBounds = cropView.contentBounds\n        let cropBoxFrame  = cropView.cropBoxFrame\n        let scale = min(contentBounds.width / cropBoxFrame.height, contentBounds.height / cropBoxFrame.width)\n        \n        // Work out which section of the image we're currently focusing at\n        let    cropMidPoint = CGPoint(x: cropBoxFrame.midX,\n                                      y: cropBoxFrame.midY)\n        var cropTargetPoint = CGPoint(x: cropMidPoint.x + cropView.scrollView.contentOffset.x,\n                                      y: cropMidPoint.y + cropView.scrollView.contentOffset.y)\n        \n        // Work out the dimensions of the crop box when rotated\n        var newCropFrame = CGRect.zero\n        \n        if (labs(cropView.angle) *  1) == ((labs(cropView.cropBoxLastEditedAngle)      )      ) ||\n           (labs(cropView.angle) * -1) == ((labs(cropView.cropBoxLastEditedAngle) - 180) % 360)\n        {\n            newCropFrame.size = cropView.cropBoxLastEditedSize\n            cropView.scrollView.minimumZoomScale = cropView.cropBoxLastEditedMinZoomScale\n            cropView.scrollView.zoomScale = cropView.cropBoxLastEditedZoomScale\n        }\n        else\n        {\n            newCropFrame.size = CGSize(width : floor(cropBoxFrame.height * scale),\n                                       height: floor(cropBoxFrame.width  * scale))\n            \n            // Re-adjust the scrolling dimensions of the scroll view to match the new size\n            cropView.scrollView.minimumZoomScale *= scale\n            cropView.scrollView.zoomScale *= scale\n        }\n        \n        newCropFrame.origin.x = floor(contentBounds.midX - (newCropFrame.width  * 0.5))\n        newCropFrame.origin.y = floor(contentBounds.midY - (newCropFrame.height * 0.5))\n        \n        // If we're animated, generate a snapshot view that we'll animate in place of the real view\n        var snapshotView: UIView? = nil\n        if (animated) {\n            snapshotView = cropView.foregroundContainerView.snapshotView(afterScreenUpdates: false)\n            cropView.rotateAnimationInProgress = true\n        }\n        \n        // Rotate the background image view, inside its container view\n        cropView.backgroundImageView.transform = rotation\n        \n        // Flip the width/height of the container view so it matches the rotated image view's size\n        let containerSize = cropView.backgroundContainerView.frame.size\n        cropView.backgroundContainerView.frame   = CGRect(origin: .zero, size: CGSize(width: containerSize.height, height: containerSize.width))\n        cropView.backgroundImageView.frame       = CGRect(origin: .zero, size: cropView.backgroundImageView.frame.size)\n        \n        \n        // Rotate the foreground image view to match\n        cropView.foregroundContainerView.transform = CGAffineTransform.identity\n        cropView.foregroundImageView.transform = rotation\n        \n        // Flip the content size of the scroll view to match the rotated bounds\n        cropView.scrollView.contentSize = cropView.backgroundContainerView.frame.size\n        \n        // Assign the new crop box frame and re-adjust the content to fill it\n        cropView.cropBoxFrame = newCropFrame\n        cropView.moveCroppedContentToCenterAnimated(false)\n        newCropFrame = cropView.cropBoxFrame\n        \n        // Work out how to line up out point of interest into the middle of the crop box\n        cropTargetPoint.x *= scale\n        cropTargetPoint.y *= scale\n        \n        // Swap the target dimensions to match a 90 degree rotation (clockwise or counterclockwise)\n        let swapValue = cropTargetPoint.x\n        \n        if (clockwise) {\n            cropTargetPoint.x = cropView.scrollView.contentSize.width  - cropTargetPoint.y\n            cropTargetPoint.y = swapValue\n        } else {\n            cropTargetPoint.x = cropTargetPoint.y\n            cropTargetPoint.y = cropView.scrollView.contentSize.height - swapValue\n        }\n        \n        // Reapply the translated scroll offset to the scroll view\n        let midPoint = CGPoint(x: newCropFrame.midX, y: newCropFrame.midY)\n        \n        var offset = CGPoint.zero\n        offset.x = floor(-midPoint.x + cropTargetPoint.x)\n        offset.y = floor(-midPoint.y + cropTargetPoint.y)\n        \n        offset.x = max(-cropView.scrollView.contentInset.left, offset.x)\n        offset.y = max(-cropView.scrollView.contentInset.top , offset.y)\n        \n        offset.x = min(cropView.scrollView.contentSize.width  - (newCropFrame.width  - cropView.scrollView.contentInset.right ), offset.x)\n        offset.y = min(cropView.scrollView.contentSize.height - (newCropFrame.height - cropView.scrollView.contentInset.bottom), offset.y)\n        \n        // If the scroll view's new scale is 1 and the new offset is equal to the old, will not trigger the delegate 'scrollViewDidScroll:'\n        // so we should call the method manually to update the foregroundImageView's frame\n        if (offset.x == cropView.scrollView.contentOffset.x && offset.y == cropView.scrollView.contentOffset.y && scale == 1) {\n            \n            cropView.matchForegroundToBackground()\n        }\n        \n        cropView.scrollView.contentOffset = offset\n        \n        // If we're animated, play an animation of the snapshot view rotating,\n        // then fade it out over the live content\n        if (animated) {\n            \n            if let snapshotView = snapshotView {\n                snapshotView.center = CGPoint(x: contentBounds.midX, y: contentBounds.midY)\n                cropView.addSubview(snapshotView)\n            }\n            \n            cropView.backgroundContainerView.isHidden = true\n            cropView.foregroundContainerView.isHidden = true\n            cropView.translucencyView.isHidden = true\n            cropView.gridOverlayView.isHidden  = true\n            \n            UIView.animate(withDuration: 0.45, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.8, options: [.beginFromCurrentState], animations: {\n                \n                let target = CGAffineTransform.identity\n                    .rotated(by: clockwise ? CGFloat(Double.pi / 2) : -CGFloat(Double.pi / 2))\n                    .scaledBy(x: scale, y: scale)\n                                \n                if let snapshotView = snapshotView {\n                    snapshotView.transform = target\n                }\n                \n            }, completion: { (complete) in\n                \n                self.cropView.backgroundContainerView.isHidden = false\n                self.cropView.foregroundContainerView.isHidden = false\n                self.cropView.translucencyView.isHidden = self.cropView.translucencyAlwaysHidden\n                self.cropView.gridOverlayView.isHidden  = false\n                \n                self.cropView.backgroundContainerView.alpha = 0.0\n                self.cropView.gridOverlayView.alpha  = 0.0\n                self.cropView.translucencyView.alpha = 1.0\n                \n                UIView.animate(withDuration: 0.45, animations: {\n                    \n                    snapshotView?.alpha = 0.0\n                    self.cropView.backgroundContainerView.alpha = 1.0\n                    self.cropView.gridOverlayView.alpha = 1.0\n                    \n                }, completion: { (complete) in\n                    \n                    self.cropView.rotateAnimationInProgress = false\n                    \n                    snapshotView?.removeFromSuperview()\n                    \n                    // If the aspect ratio lock is not enabled, allow a swap\n                    // If the aspect ratio lock is on, allow a aspect ratio swap\n                    // only if the allowDimensionSwap option is specified.\n                    let aspectRatioCanSwapDimensions =\n                        (!self.cropView.aspectRatioLockEnabled) || (self.cropView.aspectRatioLockEnabled && self.cropView.aspectRatioLockDimensionSwapEnabled)\n                    \n                    if (!aspectRatioCanSwapDimensions) {\n                        //This will animate the aspect ratio back to the desired locked ratio after the image is rotated.\n                        self.cropView.setAspectRatio(self.cropView.aspectRatio, animated: animated)\n                    }\n                })\n            })\n        }\n        \n        cropView.checkForCanReset()\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetConfiguration/CLDWidgetConfiguration.swift",
    "content": "//\n//  CLDWidgetConfiguration.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\n@objcMembers public class CLDWidgetConfiguration: NSObject {\n    \n    public var allowRotate           : Bool\n    public var initialAspectLockState: AspectRatioLockState\n    public var uploadType            : CLDUploadType\n    \n    // MARK: - init\n    /**\n    Initializes the `CLDWidgetConfiguration` instance with the specified allowRotate, initialAspectLockState and uploadType.\n     \n    - parameter allowRotate:             A boolean value specifying whether or not to allow image rotation. true by default.\n    - parameter initialAspectLockState:  Enum value specifying the initial aspect ratio lock state. enabledAndOn by default.\n    - parameter uploadType:              CLDUploadType object specifying the upload request type. signed without preset by default.\n    \n    - returns: The new `CLDWidgetConfiguration` instance.\n    */\n    public init(\n        allowRotate           : Bool = true,\n        initialAspectLockState: AspectRatioLockState = .enabledAndOff,\n        uploadType            : CLDUploadType = CLDUploadType(signed: true, preset: nil)\n    ) {\n        self.allowRotate            = allowRotate\n        self.initialAspectLockState = initialAspectLockState\n        self.uploadType             = uploadType\n        \n        super.init()\n    }\n    \n    // MARK: - AspectRatioLockState\n    /**\n    Aspect ratio lock state\n    * enabledAndOff: User can change the aspect ratio lock state - initial state is aspect ratio not locked.\n    * enabledAndOn: User can change the aspect ratio lock state - initial state is aspect ratio locked.\n    * disabled: Aspect ratio lock state button is removed. User will be able to change the aspect ratio of the image, but not the lock state.\n    */\n    @objc public enum AspectRatioLockState: Int {\n        \n        case enabledAndOff\n        case enabledAndOn\n        case disabled\n    }\n}\n\n@objcMembers public class CLDUploadType: NSObject {\n    \n    private(set) var signed: Bool\n    private(set) var preset: String?\n    \n    /**\n    Initializes the `CLDUploadType` instance with the specified signed and preset.\n     \n    - parameter signed:             A boolean value specifying whether to use signed or unsigned upload.\n    - parameter preset:             A string represents the preset for unsigned upload requests. preset MUST be set when choosing unsigned requests.\n    \n    - returns: The new `CLDUploadType` instance.\n    */\n    public init(signed: Bool, preset: String?) {\n        \n        self.signed = signed\n        self.preset = preset\n        \n        if !signed, (preset == nil || preset == String()) {\n            print(\"unsigned upload must have a predefined preset!\")\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetElements/CLDWidgetAssetContainer.swift",
    "content": "//\n//  CLDWidgetAssetContainer.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\nimport AVKit\n\nclass CLDWidgetAssetContainer: NSObject {\n    \n    enum AssetType: Int {\n        case image\n        case video\n    }\n    \n    private(set) var originalImage    : UIImage?\n                 var editedImage      : UIImage?\n    private(set) var originalVideo    : AVPlayerItem?\n                 var presentationImage: UIImage\n                 \n    private(set) var assetType        : AssetType\n    \n    init(originalImage: UIImage, editedImage: UIImage) {\n        \n        self.originalImage     = originalImage\n        self.editedImage       = editedImage\n        self.presentationImage = editedImage\n        assetType = .image\n        \n        super.init()\n    }\n    \n    init(videoUrl: URL) {\n        \n        let playerItem = AVPlayerItem(url: videoUrl)\n        self.originalVideo = playerItem\n        self.presentationImage = CLDWidgetAssetContainer.createThumbnailForVideo(playerItem: self.originalVideo)\n        \n        assetType = .video\n        \n        super.init()\n    }\n    \n    init(videoItem: AVPlayerItem) {\n        \n        self.originalVideo = videoItem\n        self.presentationImage = CLDWidgetAssetContainer.createThumbnailForVideo(playerItem: self.originalVideo)\n        \n        assetType = .video\n        \n        super.init()\n    }\n    \n    private static func createThumbnailForVideo(playerItem: AVPlayerItem?) -> UIImage {\n        \n        if let urlAsset = playerItem?.asset as? AVURLAsset {\n            \n            let url = urlAsset.url\n            let asset = AVAsset(url: url)\n            let avAssetImageGenerator = AVAssetImageGenerator(asset: asset)\n            avAssetImageGenerator.appliesPreferredTrackTransform = true\n            let thumnailTime = CMTimeMake(value: 2, timescale: 1)\n            do {\n                let cgThumbImage = try avAssetImageGenerator.copyCGImage(at: thumnailTime, actualTime: nil)\n                return UIImage(cgImage: cgThumbImage)\n            } catch {\n                print(error.localizedDescription)\n                return UIImage()\n            }\n        }\n        else {\n            return UIImage()\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetElements/CLDWidgetPreviewCollectionCell.swift",
    "content": "//\n//  CLDWidgetPreviewCollectionCell.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nclass CLDWidgetPreviewCollectionCell: UICollectionViewCell {\n    \n    var imageView: UIImageView!\n    \n    // MARK: - init\n    override init(frame: CGRect) {\n        super.init(frame: frame)\n\n        initialize()\n    }\n    \n    required init?(coder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    // MARK: - private methods\n    private func initialize() {\n        self.imageView = UIImageView(frame: self.contentView.bounds)\n        addSubview(imageView)\n        addImageViewProperties()\n    }\n    \n    private func addImageViewProperties() {\n        imageView.contentMode = .scaleAspectFill\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetImages/BackIconInstructions.swift",
    "content": "//\n//  BackIconInstructions.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nclass BackIconInstructions : CLDImageDrawingInstructions {\n    \n    var targetSize : CGSize\n    var fillColor : UIColor\n    \n    // MARK: - Initialization\n    init(targetSize size: CGSize = CGSize(width: 24.0, height: 24.0), fillColor: UIColor = .white) {\n        self.targetSize = size\n        self.fillColor = fillColor\n    }\n    \n    // MARK: - draw\n    func draw(in context: CGContext) {\n        \n        let container = CGRect(origin: .zero, size: targetSize)\n        \n        let pathBackArrowPath = UIBezierPath()\n        pathBackArrowPath.move(to: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.45833 * container.height))\n        pathBackArrowPath.addLine(to: CGPoint(x: container.minX + 0.32625 * container.width, y: container.minY + 0.45833 * container.height))\n        pathBackArrowPath.addLine(to: CGPoint(x: container.minX + 0.55917 * container.width, y: container.minY + 0.22542 * container.height))\n        pathBackArrowPath.addLine(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.16667 * container.height))\n        pathBackArrowPath.addLine(to: CGPoint(x: container.minX + 0.16667 * container.width, y: container.minY + 0.50000 * container.height))\n        pathBackArrowPath.addLine(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.83333 * container.height))\n        pathBackArrowPath.addLine(to: CGPoint(x: container.minX + 0.55875 * container.width, y: container.minY + 0.77458 * container.height))\n        pathBackArrowPath.addLine(to: CGPoint(x: container.minX + 0.32625 * container.width, y: container.minY + 0.54167 * container.height))\n        pathBackArrowPath.addLine(to: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.54167 * container.height))\n        pathBackArrowPath.addLine(to: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.45833 * container.height))\n        pathBackArrowPath.close()\n        pathBackArrowPath.usesEvenOddFillRule = true\n        fillColor.setFill()\n        pathBackArrowPath.fill()\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetImages/CropIconInstructions.swift",
    "content": "//\n//  CropIconInstructions.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nclass CropIconInstructions : CLDImageDrawingInstructions {\n    \n    var targetSize : CGSize\n    var fillColor : UIColor\n    \n    // MARK: - Initialization\n    init(targetSize size: CGSize = CGSize(width: 24.0, height: 24.0), fillColor: UIColor = .white) {\n        self.targetSize = size\n        self.fillColor = fillColor\n    }\n    \n    // MARK: - draw\n    func draw(in context: CGContext) {\n        \n        let container = CGRect(origin: .zero, size: targetSize)\n        \n        let pathCropPath = UIBezierPath()\n        pathCropPath.move(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.62500 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.79167 * container.width, y: container.minY + 0.62500 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.79167 * container.width, y: container.minY + 0.29167 * container.height))\n        pathCropPath.addCurve(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.20833 * container.height), controlPoint1: CGPoint(x: container.minX + 0.79167 * container.width, y: container.minY + 0.24583 * container.height), controlPoint2: CGPoint(x: container.minX + 0.75417 * container.width, y: container.minY + 0.20833 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.20833 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.29167 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.29167 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.62500 * container.height))\n        pathCropPath.close()\n        pathCropPath.move(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.70833 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.04167 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.20833 * container.width, y: container.minY + 0.04167 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.20833 * container.width, y: container.minY + 0.20833 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.04167 * container.width, y: container.minY + 0.20833 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.04167 * container.width, y: container.minY + 0.29167 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.20833 * container.width, y: container.minY + 0.29167 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.20833 * container.width, y: container.minY + 0.70833 * container.height))\n        pathCropPath.addCurve(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.79167 * container.height), controlPoint1: CGPoint(x: container.minX + 0.20833 * container.width, y: container.minY + 0.75417 * container.height), controlPoint2: CGPoint(x: container.minX + 0.24583 * container.width, y: container.minY + 0.79167 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.79167 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.95833 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.79167 * container.width, y: container.minY + 0.95833 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.79167 * container.width, y: container.minY + 0.79167 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.95833 * container.width, y: container.minY + 0.79167 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.95833 * container.width, y: container.minY + 0.70833 * container.height))\n        pathCropPath.addLine(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.70833 * container.height))\n        pathCropPath.close()\n        pathCropPath.usesEvenOddFillRule = true\n        fillColor.setFill()\n        pathCropPath.fill()\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetImages/CropRotateIconInstructions.swift",
    "content": "//\n//  CropRotateIconInstructions.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nclass CropRotateIconInstructions : CLDImageDrawingInstructions {\n    \n    var targetSize : CGSize\n    var fillColor : UIColor\n    \n    // MARK: - Initialization\n    init(targetSize size: CGSize = CGSize(width: 24.0, height: 24.0), fillColor: UIColor = .white) {\n        self.targetSize = size\n        self.fillColor = fillColor\n    }\n    \n    // MARK: - draw\n    func draw(in context: CGContext) {\n        \n       let container = CGRect(origin: .zero, size: targetSize)\n        \n       let pathCropRotatePath = UIBezierPath()\n        pathCropRotatePath.move(to: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.62500 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.62500 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.37500 * container.height))\n        pathCropRotatePath.addCurve(to: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.29167 * container.height), controlPoint1: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.32875 * container.height), controlPoint2: CGPoint(x: container.minX + 0.67083 * container.width, y: container.minY + 0.29167 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.29167 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.37500 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.37500 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.62500 * container.height))\n        pathCropRotatePath.close()\n        pathCropRotatePath.move(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.70833 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.20833 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.20833 * container.width, y: container.minY + 0.20833 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.20833 * container.width, y: container.minY + 0.29167 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.12500 * container.width, y: container.minY + 0.29167 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.12500 * container.width, y: container.minY + 0.37500 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.20833 * container.width, y: container.minY + 0.37500 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.20833 * container.width, y: container.minY + 0.70833 * container.height))\n        pathCropRotatePath.addCurve(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.79167 * container.height), controlPoint1: CGPoint(x: container.minX + 0.20833 * container.width, y: container.minY + 0.75417 * container.height), controlPoint2: CGPoint(x: container.minX + 0.24542 * container.width, y: container.minY + 0.79167 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.79167 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.87500 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.87500 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.79167 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.79167 * container.width, y: container.minY + 0.79167 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.79167 * container.width, y: container.minY + 0.70833 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.70833 * container.height))\n        pathCropRotatePath.close()\n        pathCropRotatePath.move(to: CGPoint(x: container.minX + 0.46042 * container.width, y: container.minY + 0.04167 * container.height))\n        pathCropRotatePath.addCurve(to: CGPoint(x: container.minX + 0.43292 * container.width, y: container.minY + 0.04333 * container.height), controlPoint1: CGPoint(x: container.minX + 0.45083 * container.width, y: container.minY + 0.04167 * container.height), controlPoint2: CGPoint(x: container.minX + 0.44208 * container.width, y: container.minY + 0.04250 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.59167 * container.width, y: container.minY + 0.20208 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.64708 * container.width, y: container.minY + 0.14667 * container.height))\n        pathCropRotatePath.addCurve(to: CGPoint(x: container.minX + 0.89583 * container.width, y: container.minY + 0.50000 * container.height), controlPoint1: CGPoint(x: container.minX + 0.78333 * container.width, y: container.minY + 0.21125 * container.height), controlPoint2: CGPoint(x: container.minX + 0.88083 * container.width, y: container.minY + 0.34333 * container.height))\n        pathCropRotatePath.addLine(to: CGPoint(x: container.minX + 0.95833 * container.width, y: container.minY + 0.50000 * container.height))\n        pathCropRotatePath.addCurve(to: CGPoint(x: container.minX + 0.46042 * container.width, y: container.minY + 0.04167 * container.height), controlPoint1: CGPoint(x: container.minX + 0.93708 * container.width, y: container.minY + 0.24333 * container.height), controlPoint2: CGPoint(x: container.minX + 0.72250 * container.width, y: container.minY + 0.04167 * container.height))\n        pathCropRotatePath.close()\n        pathCropRotatePath.usesEvenOddFillRule = true\n        fillColor.setFill()\n        pathCropRotatePath.fill()\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetImages/DoneIconInstructions.swift",
    "content": "//\n//  DoneIconInstructions.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nclass DoneIconInstructions : CLDImageDrawingInstructions {\n    \n    var targetSize         : CGSize\n    var fillColor          : UIColor\n    var ovalBackgroundColor: UIColor\n        \n    // MARK: - Initialization\n    init(targetSize size: CGSize = CGSize(width: 60.0, height: 60.0), fillColor: UIColor = .white, ovalBackgroundColor: UIColor = UIColor(red: 38.0/255, green: 91.0/255, blue: 220.0/255, alpha: 1.0)) {\n        self.targetSize          = size\n        self.fillColor           = fillColor\n        self.ovalBackgroundColor = ovalBackgroundColor\n    }\n    \n    // MARK: - draw\n    func draw(in context: CGContext) {\n        \n        let container  = CGRect(origin: .zero, size: targetSize)\n        let vContainer = CGRect(origin: .zero, size: CGSize(width: targetSize.width/2, height: targetSize.height/2))\n        \n        // This non-generic function dramatically improves compilation times of complex expressions.\n        func fastFloor(_ x: CGFloat) -> CGFloat { return floor(x) }\n\n        // Oval Drawing\n        let ovalPath = UIBezierPath(ovalIn: CGRect(x: container.minX + fastFloor(container.width * 0.00000 + 0.5), y: container.minY + fastFloor(container.height * 0.00000 + 0.5), width: fastFloor(container.width * 1.00000 + 0.5) - fastFloor(container.width * 0.00000 + 0.5), height: fastFloor(container.height * 1.00000 + 0.5) - fastFloor(container.height * 0.00000 + 0.5)))\n        ovalBackgroundColor.setFill()\n        ovalPath.fill()\n        \n        //// pathDone Drawing\n        let pathDonePath = UIBezierPath()\n        pathDonePath.move(to: CGPoint(x: vContainer.midX + 0.37500 * vContainer.width, y: vContainer.midY + 0.67500 * vContainer.height))\n        pathDonePath.addLine(to: CGPoint(x: vContainer.midX + 0.20000 * vContainer.width, y: vContainer.midY + 0.50000 * vContainer.height))\n        pathDonePath.addLine(to: CGPoint(x: vContainer.midX + 0.14167 * vContainer.width, y: vContainer.midY + 0.55833 * vContainer.height))\n        pathDonePath.addLine(to: CGPoint(x: vContainer.midX + 0.37500 * vContainer.width, y: vContainer.midY + 0.79167 * vContainer.height))\n        pathDonePath.addLine(to: CGPoint(x: vContainer.midX + 0.87500 * vContainer.width, y: vContainer.midY + 0.29167 * vContainer.height))\n        pathDonePath.addLine(to: CGPoint(x: vContainer.midX + 0.81667 * vContainer.width, y: vContainer.midY + 0.23333 * vContainer.height))\n        pathDonePath.addLine(to: CGPoint(x: vContainer.midX + 0.37500 * vContainer.width, y: vContainer.midY + 0.67500 * vContainer.height))\n        pathDonePath.close()\n        pathDonePath.usesEvenOddFillRule = true\n        fillColor.setFill()\n        pathDonePath.fill()\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetImages/RatioLockedIconInstructions.swift",
    "content": "//\n//  RatioLockedIconInstructions.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nclass RatioLockedIconInstructions : CLDImageDrawingInstructions {\n    \n    var targetSize : CGSize\n    var fillColor : UIColor\n    \n    // MARK: - Initialization\n    init(targetSize size: CGSize = CGSize(width: 24.0, height: 24.0), fillColor: UIColor = .white) {\n        self.targetSize = size\n        self.fillColor = fillColor\n    }\n    \n    // MARK: - draw\n    func draw(in context: CGContext) {\n        \n        let container = CGRect(origin: .zero, size: targetSize)\n        \n        let pathRatioLockedPath = UIBezierPath()\n        pathRatioLockedPath.move(to: CGPoint(x: container.minX + 0.75000 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioLockedPath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioLockedPath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.25000 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.04167 * container.height), controlPoint1: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.13500 * container.height), controlPoint2: CGPoint(x: container.minX + 0.61500 * container.width, y: container.minY + 0.04167 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.25000 * container.height), controlPoint1: CGPoint(x: container.minX + 0.38500 * container.width, y: container.minY + 0.04167 * container.height), controlPoint2: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.13500 * container.height))\n        pathRatioLockedPath.addLine(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioLockedPath.addLine(to: CGPoint(x: container.minX + 0.25000 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.16667 * container.width, y: container.minY + 0.41667 * container.height), controlPoint1: CGPoint(x: container.minX + 0.20417 * container.width, y: container.minY + 0.33333 * container.height), controlPoint2: CGPoint(x: container.minX + 0.16667 * container.width, y: container.minY + 0.37083 * container.height))\n        pathRatioLockedPath.addLine(to: CGPoint(x: container.minX + 0.16667 * container.width, y: container.minY + 0.83333 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.25000 * container.width, y: container.minY + 0.91667 * container.height), controlPoint1: CGPoint(x: container.minX + 0.16667 * container.width, y: container.minY + 0.87917 * container.height), controlPoint2: CGPoint(x: container.minX + 0.20417 * container.width, y: container.minY + 0.91667 * container.height))\n        pathRatioLockedPath.addLine(to: CGPoint(x: container.minX + 0.75000 * container.width, y: container.minY + 0.91667 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.83333 * container.height), controlPoint1: CGPoint(x: container.minX + 0.79583 * container.width, y: container.minY + 0.91667 * container.height), controlPoint2: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.87917 * container.height))\n        pathRatioLockedPath.addLine(to: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.41667 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.75000 * container.width, y: container.minY + 0.33333 * container.height), controlPoint1: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.37083 * container.height), controlPoint2: CGPoint(x: container.minX + 0.79583 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioLockedPath.close()\n        pathRatioLockedPath.move(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.70833 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.41667 * container.width, y: container.minY + 0.62500 * container.height), controlPoint1: CGPoint(x: container.minX + 0.45417 * container.width, y: container.minY + 0.70833 * container.height), controlPoint2: CGPoint(x: container.minX + 0.41667 * container.width, y: container.minY + 0.67083 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.54167 * container.height), controlPoint1: CGPoint(x: container.minX + 0.41667 * container.width, y: container.minY + 0.57917 * container.height), controlPoint2: CGPoint(x: container.minX + 0.45417 * container.width, y: container.minY + 0.54167 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.58333 * container.width, y: container.minY + 0.62500 * container.height), controlPoint1: CGPoint(x: container.minX + 0.54583 * container.width, y: container.minY + 0.54167 * container.height), controlPoint2: CGPoint(x: container.minX + 0.58333 * container.width, y: container.minY + 0.57917 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.70833 * container.height), controlPoint1: CGPoint(x: container.minX + 0.58333 * container.width, y: container.minY + 0.67083 * container.height), controlPoint2: CGPoint(x: container.minX + 0.54583 * container.width, y: container.minY + 0.70833 * container.height))\n        pathRatioLockedPath.close()\n        pathRatioLockedPath.move(to: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioLockedPath.addLine(to: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.25000 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.12500 * container.height), controlPoint1: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.18083 * container.height), controlPoint2: CGPoint(x: container.minX + 0.43083 * container.width, y: container.minY + 0.12500 * container.height))\n        pathRatioLockedPath.addCurve(to: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.25000 * container.height), controlPoint1: CGPoint(x: container.minX + 0.56917 * container.width, y: container.minY + 0.12500 * container.height), controlPoint2: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.18083 * container.height))\n        pathRatioLockedPath.addLine(to: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioLockedPath.addLine(to: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioLockedPath.close()\n        pathRatioLockedPath.usesEvenOddFillRule = true\n        fillColor.setFill()\n        pathRatioLockedPath.fill()\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetImages/RatioOpenedIconInstructions.swift",
    "content": "//\n//  RatioOpenedIconInstructions.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nclass RatioOpenedIconInstructions : CLDImageDrawingInstructions {\n    \n    var targetSize : CGSize\n    var fillColor : UIColor\n    \n    // MARK: - Initialization\n    init(targetSize size: CGSize = CGSize(width: 24.0, height: 24.0), fillColor: UIColor = .white) {\n        self.targetSize = size\n        self.fillColor = fillColor\n    }\n    \n    // MARK: - draw\n    func draw(in context: CGContext) {\n        \n        let container = CGRect(origin: .zero, size: targetSize)\n        \n        let pathRatioOpenedPath = UIBezierPath()\n        pathRatioOpenedPath.move(to: CGPoint(x: container.minX + 0.75000 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.25000 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.04167 * container.height), controlPoint1: CGPoint(x: container.minX + 0.70833 * container.width, y: container.minY + 0.13500 * container.height), controlPoint2: CGPoint(x: container.minX + 0.61500 * container.width, y: container.minY + 0.04167 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.25000 * container.height), controlPoint1: CGPoint(x: container.minX + 0.38500 * container.width, y: container.minY + 0.04167 * container.height), controlPoint2: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.13500 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.29167 * container.width, y: container.minY + 0.25000 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.25000 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.25000 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.12500 * container.height), controlPoint1: CGPoint(x: container.minX + 0.37500 * container.width, y: container.minY + 0.18083 * container.height), controlPoint2: CGPoint(x: container.minX + 0.43083 * container.width, y: container.minY + 0.12500 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.25000 * container.height), controlPoint1: CGPoint(x: container.minX + 0.56917 * container.width, y: container.minY + 0.12500 * container.height), controlPoint2: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.18083 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.62500 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.25000 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.16667 * container.width, y: container.minY + 0.41667 * container.height), controlPoint1: CGPoint(x: container.minX + 0.20417 * container.width, y: container.minY + 0.33333 * container.height), controlPoint2: CGPoint(x: container.minX + 0.16667 * container.width, y: container.minY + 0.37083 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.16667 * container.width, y: container.minY + 0.83333 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.25000 * container.width, y: container.minY + 0.91667 * container.height), controlPoint1: CGPoint(x: container.minX + 0.16667 * container.width, y: container.minY + 0.87917 * container.height), controlPoint2: CGPoint(x: container.minX + 0.20417 * container.width, y: container.minY + 0.91667 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.75000 * container.width, y: container.minY + 0.91667 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.83333 * container.height), controlPoint1: CGPoint(x: container.minX + 0.79583 * container.width, y: container.minY + 0.91667 * container.height), controlPoint2: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.87917 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.41667 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.75000 * container.width, y: container.minY + 0.33333 * container.height), controlPoint1: CGPoint(x: container.minX + 0.83333 * container.width, y: container.minY + 0.37083 * container.height), controlPoint2: CGPoint(x: container.minX + 0.79583 * container.width, y: container.minY + 0.33333 * container.height))\n        pathRatioOpenedPath.close()\n        pathRatioOpenedPath.move(to: CGPoint(x: container.minX + 0.75000 * container.width, y: container.minY + 0.83333 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.25000 * container.width, y: container.minY + 0.83333 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.25000 * container.width, y: container.minY + 0.41667 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.75000 * container.width, y: container.minY + 0.41667 * container.height))\n        pathRatioOpenedPath.addLine(to: CGPoint(x: container.minX + 0.75000 * container.width, y: container.minY + 0.83333 * container.height))\n        pathRatioOpenedPath.close()\n        pathRatioOpenedPath.move(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.70833 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.58333 * container.width, y: container.minY + 0.62500 * container.height), controlPoint1: CGPoint(x: container.minX + 0.54583 * container.width, y: container.minY + 0.70833 * container.height), controlPoint2: CGPoint(x: container.minX + 0.58333 * container.width, y: container.minY + 0.67083 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.54167 * container.height), controlPoint1: CGPoint(x: container.minX + 0.58333 * container.width, y: container.minY + 0.57917 * container.height), controlPoint2: CGPoint(x: container.minX + 0.54583 * container.width, y: container.minY + 0.54167 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.41667 * container.width, y: container.minY + 0.62500 * container.height), controlPoint1: CGPoint(x: container.minX + 0.45417 * container.width, y: container.minY + 0.54167 * container.height), controlPoint2: CGPoint(x: container.minX + 0.41667 * container.width, y: container.minY + 0.57917 * container.height))\n        pathRatioOpenedPath.addCurve(to: CGPoint(x: container.minX + 0.50000 * container.width, y: container.minY + 0.70833 * container.height), controlPoint1: CGPoint(x: container.minX + 0.41667 * container.width, y: container.minY + 0.67083 * container.height), controlPoint2: CGPoint(x: container.minX + 0.45417 * container.width, y: container.minY + 0.70833 * container.height))\n        pathRatioOpenedPath.close()\n        pathRatioOpenedPath.usesEvenOddFillRule = true\n        fillColor.setFill()\n        pathRatioOpenedPath.fill()\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetImages/RotateIconInstructions.swift",
    "content": "//\n//  RotateIconInstructions.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nclass RotateIconInstructions : CLDImageDrawingInstructions {\n    \n    var targetSize : CGSize\n    var fillColor : UIColor\n    \n    // MARK: - Initialization\n    init(targetSize size: CGSize = CGSize(width: 24.0, height: 24.0), fillColor: UIColor = .white) {\n        self.targetSize = size\n        self.fillColor = fillColor\n    }\n    \n    // MARK: - draw\n    func draw(in context: CGContext) {\n        \n        let container = CGRect(origin: .zero, size: targetSize)\n        \n       let pathRotatePath = UIBezierPath()\n        pathRotatePath.move(to: CGPoint(x: container.minX + 0.30583 * container.width, y: container.minY + 0.26708 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.03583 * container.width, y: container.minY + 0.53750 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.30625 * container.width, y: container.minY + 0.80750 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.57667 * container.width, y: container.minY + 0.53750 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.30583 * container.width, y: container.minY + 0.26708 * container.height))\n        pathRotatePath.close()\n        pathRotatePath.move(to: CGPoint(x: container.minX + 0.15375 * container.width, y: container.minY + 0.53750 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.30625 * container.width, y: container.minY + 0.38500 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.45833 * container.width, y: container.minY + 0.53750 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.30583 * container.width, y: container.minY + 0.69000 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.15375 * container.width, y: container.minY + 0.53750 * container.height))\n        pathRotatePath.close()\n        pathRotatePath.move(to: CGPoint(x: container.minX + 0.80667 * container.width, y: container.minY + 0.27667 * container.height))\n        pathRotatePath.addCurve(to: CGPoint(x: container.minX + 0.54167 * container.width, y: container.minY + 0.16667 * container.height), controlPoint1: CGPoint(x: container.minX + 0.73375 * container.width, y: container.minY + 0.20333 * container.height), controlPoint2: CGPoint(x: container.minX + 0.63750 * container.width, y: container.minY + 0.16667 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.54167 * container.width, y: container.minY + 0.03167 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.36500 * container.width, y: container.minY + 0.20833 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.54167 * container.width, y: container.minY + 0.38500 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.54167 * container.width, y: container.minY + 0.25000 * container.height))\n        pathRotatePath.addCurve(to: CGPoint(x: container.minX + 0.74792 * container.width, y: container.minY + 0.33542 * container.height), controlPoint1: CGPoint(x: container.minX + 0.61625 * container.width, y: container.minY + 0.25000 * container.height), controlPoint2: CGPoint(x: container.minX + 0.69083 * container.width, y: container.minY + 0.27833 * container.height))\n        pathRotatePath.addCurve(to: CGPoint(x: container.minX + 0.74792 * container.width, y: container.minY + 0.74792 * container.height), controlPoint1: CGPoint(x: container.minX + 0.86167 * container.width, y: container.minY + 0.44917 * container.height), controlPoint2: CGPoint(x: container.minX + 0.86167 * container.width, y: container.minY + 0.63417 * container.height))\n        pathRotatePath.addCurve(to: CGPoint(x: container.minX + 0.54167 * container.width, y: container.minY + 0.83333 * container.height), controlPoint1: CGPoint(x: container.minX + 0.69083 * container.width, y: container.minY + 0.80500 * container.height), controlPoint2: CGPoint(x: container.minX + 0.61625 * container.width, y: container.minY + 0.83333 * container.height))\n        pathRotatePath.addCurve(to: CGPoint(x: container.minX + 0.42333 * container.width, y: container.minY + 0.80792 * container.height), controlPoint1: CGPoint(x: container.minX + 0.50125 * container.width, y: container.minY + 0.83333 * container.height), controlPoint2: CGPoint(x: container.minX + 0.46083 * container.width, y: container.minY + 0.82458 * container.height))\n        pathRotatePath.addLine(to: CGPoint(x: container.minX + 0.36125 * container.width, y: container.minY + 0.87000 * container.height))\n        pathRotatePath.addCurve(to: CGPoint(x: container.minX + 0.54167 * container.width, y: container.minY + 0.91667 * container.height), controlPoint1: CGPoint(x: container.minX + 0.41750 * container.width, y: container.minY + 0.90083 * container.height), controlPoint2: CGPoint(x: container.minX + 0.47958 * container.width, y: container.minY + 0.91667 * container.height))\n        pathRotatePath.addCurve(to: CGPoint(x: container.minX + 0.80667 * container.width, y: container.minY + 0.80667 * container.height), controlPoint1: CGPoint(x: container.minX + 0.63750 * container.width, y: container.minY + 0.91667 * container.height), controlPoint2: CGPoint(x: container.minX + 0.73375 * container.width, y: container.minY + 0.88000 * container.height))\n        pathRotatePath.addCurve(to: CGPoint(x: container.minX + 0.80667 * container.width, y: container.minY + 0.27667 * container.height), controlPoint1: CGPoint(x: container.minX + 0.95333 * container.width, y: container.minY + 0.66042 * container.height), controlPoint2: CGPoint(x: container.minX + 0.95333 * container.width, y: container.minY + 0.42292 * container.height))\n        pathRotatePath.close()\n        pathRotatePath.usesEvenOddFillRule = true\n        fillColor.setFill()\n        pathRotatePath.fill()\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetVideo/CLDDisplayLinkObserver.swift",
    "content": "//\n//  CLDDisplayLinkObservers.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nprotocol CLDDisplayLinkObserverDelegate: AnyObject {\n    func displayLinkObserverDidTick(_ linkObserver: CLDDisplayLinkObserver)\n}\n\nclass CLDDisplayLinkObserver: NSObject {\n    \n    private(set) var tickerTimestamp  : CFTimeInterval\n    private(set) var displayLinkTicker: CADisplayLink?\n    \n    var delayValue   : Double\n    \n    weak var delegate: CLDDisplayLinkObserverDelegate?\n    \n    // MARK: - Init\n    init(delegate: CLDDisplayLinkObserverDelegate?) {\n        \n        self.delayValue        = 0.0\n        self.tickerTimestamp   = CFTimeInterval(0.0)\n        self.displayLinkTicker = nil\n        super.init()\n        \n        self.delegate = delegate\n    }\n\n    deinit {\n        stopTicker()\n    }\n\n    // MARK: - private methods\n    @objc fileprivate func updateTicker(with displayLink: CADisplayLink) {\n        \n        guard tickerTimestamp != 0.0 else { tickerTimestamp = displayLink.timestamp ; return }\n        let delta = displayLink.timestamp - tickerTimestamp\n        guard delta >= delayValue else { return }\n        delegate?.displayLinkObserverDidTick(self)\n        tickerTimestamp = displayLink.timestamp\n    }\n}\n\n// MARK: - internal methods\nextension CLDDisplayLinkObserver {\n    \n    func startTicker() {\n        \n        guard displayLinkTicker == nil else { return }\n        let displayLink = CADisplayLink(target: self, selector: #selector(updateTicker(with:)))\n        displayLink.add(to: RunLoop.main, forMode: RunLoop.Mode.common)\n        displayLink.add(to: RunLoop.main, forMode: RunLoop.Mode.tracking)\n        displayLinkTicker = displayLink\n    }\n    \n    func stopTicker() {\n        \n        displayLinkTicker?.remove(from: RunLoop.main, forMode: RunLoop.Mode.common)\n        displayLinkTicker?.remove(from: RunLoop.main, forMode: RunLoop.Mode.tracking)\n        displayLinkTicker?.invalidate()\n        displayLinkTicker = nil\n        tickerTimestamp = 0.0\n    }\n    \n    func isValid() -> Bool {\n        return displayLinkTicker != nil\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetVideo/CLDVideoControlsState.swift",
    "content": "//\n//  CLDVideoControlsState.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\nprotocol CLDVideoControlsState: AnyObject {\n    \n    var controlsView: CLDVideoControlsView { get set }\n    \n    init(controlsView: CLDVideoControlsView)\n    \n    func playPausePressed()\n    func backgroundPressed()\n    func timerFinished()\n    func videoEnded()\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetVideo/CLDVideoControlsView.swift",
    "content": "//\n//  CLDVideoControlsView.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\nprotocol CLDVideoControlsViewDelegate: AnyObject {\n    func playPressedOnVideoControls (_ videoControls: CLDVideoControlsView)\n    func pausePressedOnVideoControls(_ videoControls: CLDVideoControlsView)\n}\n\nclass CLDVideoControlsView: UIControl {\n \n      \n    private(set) var playPauseButton  : UIButton!\n    private(set) var visibilityTimer  : CLDDisplayLinkObserver!\n    \n    weak         var delegate         : CLDVideoControlsViewDelegate?\n    \n    private(set) var currentState         : CLDVideoControlsState!\n    private(set) var shownAndPlayingState : CLDVideoControlsState!\n    private(set) var shownAndPausedState  : CLDVideoControlsState!\n    private(set) var hiddenAndPlayingState: CLDVideoControlsState!\n    private(set) var hiddenAndPausedState : CLDVideoControlsState!\n    \n    private let transparentBackgroundColor = UIColor.black.withAlphaComponent(0.5)\n    private let controlTransitionsDuration = 0.2\n    private let controlAppearanceDuration  = 2.5\n    \n    // MARK: - init\n    init(frame: CGRect, delegate: CLDVideoControlsViewDelegate?) {\n    \n        self.delegate  = delegate\n        \n        super.init(frame: frame)\n        \n        // handle state\n        shownAndPlayingState  = CLDVideoShownAndPlayingState (controlsView: self)\n        shownAndPausedState   = CLDVideoShownAndPausedState  (controlsView: self)\n        hiddenAndPlayingState = CLDVideoHiddenAndPlayingState(controlsView: self)\n        hiddenAndPausedState  = CLDVideoHiddenAndPausedState (controlsView: self)\n        currentState          = shownAndPlayingState\n        \n        // initial timer state\n        visibilityTimer = CLDDisplayLinkObserver(delegate: self)\n        startTimer()\n        \n        addTarget(self, action: #selector(backgroundPressed), for: .touchUpInside)\n        \n        createUI()\n    }\n    \n    required init?(coder: NSCoder) { fatalError(\"init(coder:) has not been implemented\") }\n    \n    func resetControls() {\n        \n        currentState = shownAndPlayingState\n        showControls()\n        playVideo()\n    }\n}\n\n// MARK: - handle events\nextension CLDVideoControlsView {\n    \n    @objc private func backgroundPressed() {\n        currentState.backgroundPressed()\n    }\n    \n    @objc private func playPausePressed() {\n        currentState.playPausePressed()\n    }\n    \n    func videoEnded() {\n        currentState.videoEnded()\n    }\n    \n    func pauseVideo() {\n        \n        delegate?.pausePressedOnVideoControls(self)\n        playPauseButton.setTitle(\"▶\", for: .normal)\n        stopTimer()\n    }\n    \n    func playVideo() {\n        \n        delegate?.playPressedOnVideoControls(self)\n        playPauseButton.setTitle(\"||\", for: .normal)\n        startTimer()\n    }\n}\n\n// MARK: - handle state\nextension CLDVideoControlsView {\n    \n    func setNewState(newState: CLDVideoControlsState) {\n        currentState = newState\n    }\n}\n\n// MARK: - display link timer\nextension CLDVideoControlsView: CLDDisplayLinkObserverDelegate {\n    \n    func startTimer() {\n        visibilityTimer.stopTicker()\n        visibilityTimer.delayValue = controlAppearanceDuration\n        visibilityTimer.startTicker()\n    }\n    \n    func stopTimer() {\n        visibilityTimer.stopTicker()\n    }\n    \n    func displayLinkObserverDidTick(_ linkObserver: CLDDisplayLinkObserver) {\n        currentState.timerFinished()\n    }\n}\n\n// MARK: - UI\nextension CLDVideoControlsView {\n    \n    private func createUI() {\n        \n        backgroundColor = transparentBackgroundColor\n        \n        playPauseButton = UIButton(type: .custom)\n        playPauseButton.accessibilityIdentifier = \"videoViewPausePlayButton\"\n        playPauseButton.setTitle(\"||\", for: .normal)\n        playPauseButton.addTarget(self, action: #selector(playPausePressed), for: .touchUpInside)\n        playPauseButton.titleLabel?.font = playPauseButton.titleLabel?.font.withSize(40)\n        addSubview(playPauseButton)\n        playPauseButton.cld_addConstraintsToCenter(self)\n    }\n    \n    func showControls() {\n        \n        UIView.animate(withDuration: controlTransitionsDuration, animations: {\n            \n            self.backgroundColor       = self.transparentBackgroundColor\n            self.playPauseButton.alpha = 1.0\n        })\n    }\n    \n    func hideControls() {\n        \n        // we dont set the background alpha to 0 in order to keep getting touch events\n        UIView.animate(withDuration: controlTransitionsDuration, animations: {\n            \n            self.backgroundColor       = UIColor.clear\n            self.playPauseButton.alpha = 0.0\n        })\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetVideo/CLDVideoHiddenAndPausedState.swift",
    "content": "//\n//  CLDVideoHiddenAndPausedState.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\nclass CLDVideoHiddenAndPausedState: NSObject, CLDVideoControlsState {\n    \n    var controlsView: CLDVideoControlsView\n    \n    required init(controlsView: CLDVideoControlsView) {\n        \n        self.controlsView = controlsView\n        super.init()\n    }\n    \n    func playPausePressed() {\n        print(\"playPausePressed shouldn't be called in CLDVideoHiddenAndPausedState\")\n    }\n    \n    func backgroundPressed() {\n        \n        controlsView.setNewState(newState: controlsView.shownAndPausedState)\n        controlsView.stopTimer()\n        \n        controlsView.showControls()\n    }\n    \n    func timerFinished() {\n        print(\"timerFinished shouldn't be called in CLDVideoHiddenAndPausedState\")\n    }\n    \n    func videoEnded() {\n        print(\"videoEnded shouldn't be called in CLDVideoHiddenAndPausedState\")\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetVideo/CLDVideoHiddenAndPlayingState.swift",
    "content": "//\n//  CLDVideoHiddenAndPlayingState.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\nclass CLDVideoHiddenAndPlayingState: NSObject, CLDVideoControlsState {\n    \n    var controlsView: CLDVideoControlsView\n    \n    required init(controlsView: CLDVideoControlsView) {\n        \n        self.controlsView = controlsView\n        super.init()\n    }\n    \n    func playPausePressed() {\n        print(\"playPausePressed shouldn't be called in CLDVideoHiddenAndPlayingState\")\n    }\n    \n    func backgroundPressed() {\n                \n        controlsView.setNewState(newState: controlsView.shownAndPlayingState)\n        controlsView.startTimer()\n        \n        controlsView.showControls()\n    }\n    \n    func timerFinished() {\n        print(\"timerFinished shouldn't be called in CLDVideoHiddenAndPlayingState\")\n    }\n    \n    func videoEnded() {\n\n        controlsView.pauseVideo()\n        \n        controlsView.setNewState(newState: controlsView.shownAndPausedState)\n        \n        controlsView.showControls()\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetVideo/CLDVideoPlayerView.swift",
    "content": "//\n//  CLDVideoPlayerView.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\nimport AVKit\n\nclass CLDVideoPlayerView: UIView {\n\n    override class var layerClass: AnyClass {\n        return AVPlayerLayer.self\n    }\n    \n    var player : AVPlayer? {\n        get {\n            return playerLayer?.player\n        }\n        set {\n            playerLayer?.player = newValue\n        }\n    }\n    \n    weak var playerLayer : AVPlayerLayer? {\n        guard let layer = layer as? AVPlayerLayer else { return nil }\n        return layer as AVPlayerLayer\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetVideo/CLDVideoShownAndPausedState.swift",
    "content": "//\n//  CLDVideoShownAndPausedState.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\nclass CLDVideoShownAndPausedState: NSObject, CLDVideoControlsState {\n    \n    var controlsView: CLDVideoControlsView\n    \n    required init(controlsView: CLDVideoControlsView) {\n        \n        self.controlsView = controlsView\n        super.init()\n    }\n    \n    func playPausePressed() {\n        \n        controlsView.playVideo()\n        \n        controlsView.setNewState(newState: controlsView.shownAndPlayingState)\n    }\n    \n    func backgroundPressed() {\n                \n        controlsView.setNewState(newState: controlsView.hiddenAndPausedState)\n        \n        controlsView.hideControls()\n    }\n    \n    func timerFinished() {\n        print(\"timerFinished shouldn't be called in CLDVideoShownAndPausedState\")\n    }\n    \n    func videoEnded() {\n        print(\"videoEnded shouldn't be called in CLDVideoShownAndPausedState\")\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetVideo/CLDVideoShownAndPlayingState.swift",
    "content": "//\n//  CLDVideoShownAndPlayingState.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\nclass CLDVideoShownAndPlayingState: NSObject, CLDVideoControlsState {\n    \n    var controlsView: CLDVideoControlsView\n    \n    required init(controlsView: CLDVideoControlsView) {\n        \n        self.controlsView = controlsView\n        super.init()\n    }\n    \n    func playPausePressed() {\n        \n        controlsView.pauseVideo()\n        controlsView.setNewState(newState: controlsView.shownAndPausedState)\n    }\n    \n    func backgroundPressed() {\n        hideControls()\n    }\n    \n    func timerFinished() {\n        hideControls()\n    }\n    \n    private func hideControls() {\n\n        controlsView.stopTimer()\n        controlsView.setNewState(newState: controlsView.hiddenAndPlayingState)\n        \n        controlsView.hideControls()\n    }\n    \n    func videoEnded() {\n        \n        controlsView.pauseVideo()\n        \n        controlsView.setNewState(newState: controlsView.shownAndPausedState)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetVideo/CLDVideoView.swift",
    "content": "//\n//  CLDVideoView.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\nimport AVKit\n\nclass CLDVideoView: UIView {\n\n    private(set) var videoControlsView: CLDVideoControlsView!\n    private(set) var videoPlayerView  : CLDVideoPlayerView!\n    private(set) var player           : AVPlayer\n    \n    /**\n    Initializes the CLDVideoView\n\n    - parameter frame:         The view's frame\n    - parameter player:        The player for the presented video\n\n    - returns:                 A new CLDVideoView instance.\n    */\n    init(frame: CGRect, playerItem: AVPlayerItem?, isMuted: Bool) {\n        \n        self.player = AVPlayer(playerItem: playerItem)\n        self.player.isMuted = isMuted\n        \n        super.init(frame: frame)\n        \n        createUI()\n    }\n\n    required init?(coder: NSCoder) { fatalError(\"init(coder:) has not been implemented\") }\n    \n    /**\n    Plays a new video and adjust the controls\n\n    - parameter item:         The new AVPlayerItem to play\n    */\n    func replaceCurrentItem(with item: AVPlayerItem) {\n\n        player.seek(to: CMTime.zero)\n        player.replaceCurrentItem(with: item)\n        videoControlsView.resetControls()\n    }\n    \n    /**\n    Pausing the video player\n    */\n    func pauseVideo() {\n        player.pause()\n    }\n}\n\n// MARK: - CLDVideoControlsViewDelegate\nextension CLDVideoView: CLDVideoControlsViewDelegate {\n    \n    func playPressedOnVideoControls(_ videoControls: CLDVideoControlsView) {\n        player.play()\n    }\n    \n    func pausePressedOnVideoControls(_ videoControls: CLDVideoControlsView) {\n        player.pause()\n    }\n}\n\n// MARK: - create UI\nextension CLDVideoView {\n    \n    private func createUI() {\n        \n        videoControlsView = CLDVideoControlsView(frame: frame, delegate: self)\n        videoControlsView.accessibilityIdentifier = \"videoControlsView\"\n        videoPlayerView   = CLDVideoPlayerView  (frame: frame)\n        videoPlayerView.accessibilityIdentifier = \"videoPlayerView\"\n        \n        addSubview(videoPlayerView)\n        addSubview(videoControlsView)\n        \n        videoPlayerView  .cld_addConstraintsToFill(self)\n        videoControlsView.cld_addConstraintsToFill(self)\n        \n        guard let playerLayer = videoPlayerView.playerLayer else { return }\n        playerLayer.player = player\n        \n        NotificationCenter.default.addObserver(self, selector: #selector(videoEnded), name: .AVPlayerItemDidPlayToEndTime, object: nil)\n        player.play()\n    }\n    \n    @objc private func videoEnded() {\n        \n        player.seek(to: CMTime.zero)\n        videoControlsView.videoEnded()\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetViewControllers/CLDWidgetEditViewController.swift",
    "content": "//\n//  CLDWidgetEditViewController.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\ninternal protocol CLDWidgetEditDelegate: AnyObject {\n    func widgetEditViewController(_ controller: CLDWidgetEditViewController, didFinishEditing image: CLDWidgetAssetContainer)\n    func widgetEditViewControllerDidReset (_ controller: CLDWidgetEditViewController)\n    func widgetEditViewControllerDidCancel(_ controller: CLDWidgetEditViewController)\n}\n\ninternal class CLDWidgetEditViewController: UIViewController {\n    \n    private(set) var buttonsView : UIView!\n    private(set) var cancelButton: UIButton!\n    private(set) var rotateButton: UIButton!\n    private(set) var doneButton  : UIButton!\n    private(set) var cropView    : CLDCropView!\n    \n    private(set)  var image                 : CLDWidgetAssetContainer\n    private(set)  var configuration         : CLDWidgetConfiguration?\n    private(set)  var initialAspectLockState: CLDWidgetConfiguration.AspectRatioLockState\n    internal weak var delegate              : CLDWidgetEditDelegate?\n    \n    private var firstTime               : Bool = true\n    private let bottomCropViewPadding   : CGFloat = 10\n    private let bottomButtonsViewPadding: CGFloat = 10\n    \n    // MARK: - init\n    init(\n        image: CLDWidgetAssetContainer,\n        configuration: CLDWidgetConfiguration? = nil,\n        delegate: CLDWidgetEditDelegate? = nil,\n        initialAspectLockState: CLDWidgetConfiguration.AspectRatioLockState = .enabledAndOff\n    ) {\n        self.image                  = image\n        self.configuration          = configuration\n        self.delegate               = delegate\n        self.initialAspectLockState = initialAspectLockState\n        \n        super.init(nibName: nil, bundle: nil)\n        \n        if #available(iOS 11.0, *) {} else {\n            automaticallyAdjustsScrollViewInsets = false\n        }\n    }\n    \n    required init?(coder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    override func loadView() {\n        \n        super.loadView()\n        createUI()\n    }\n    \n    override func viewDidLayoutSubviews() {\n        super.viewDidLayoutSubviews()\n        \n        adjustCropViewLocation(cropView)\n        \n        if firstTime {\n            firstTime = false\n            cropView.performInitialSetup()\n        }\n    }\n}\n\n// MARK: - crop view\nextension CLDWidgetEditViewController {\n    \n    private func frameForCropView() -> CGRect {\n        \n        let bounds = view.bounds\n        var frame  = CGRect.zero\n        \n        frame.size.height = bounds.height - buttonsView.frame.height - bottomButtonsViewPadding - bottomCropViewPadding\n        frame.size.width  = bounds.width\n        \n        return frame\n    }\n    \n    func aspectRatioLockPressed() {\n        \n        cropView.aspectRatioLockEnabled.toggle()\n        if cropView.aspectRatioLockEnabled {\n            cropView.lockAspectRatio(to: cropView.cropBoxFrame.size)\n        }\n    }\n}\n\n// MARK: - actions\nprivate extension CLDWidgetEditViewController {\n    \n    @objc func resetPressed(sender: UIButton) {\n        \n        image.editedImage = image.originalImage\n        \n        // crete a new crop view with original image\n        let oldView = cropView\n        let newView = createCropView(for: image.originalImage!, aspectLockState: initialAspectLockState == .enabledAndOn)\n        \n        view.insertSubview(newView, belowSubview: cropView)\n        \n        adjustCropViewLocation(newView)\n        newView.performInitialSetup()\n        newView.alpha = 0.0\n        \n        cropView = newView\n        \n        UIView.animateKeyframes(withDuration: 1, delay: 0.0, options: [], animations: {\n            \n            UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 0.4) {\n                oldView?.alpha = 0.0\n            }\n            UIView.addKeyframe(withRelativeStartTime: 0.6, relativeDuration: 0.4) {\n                newView.alpha  = 1.0\n            }\n            \n        }) { (success) in\n            oldView?.isHidden = true\n            oldView?.removeFromSuperview()\n        }\n        \n        cropView.aspectRatioLockEnabled = false\n        \n        delegate?.widgetEditViewControllerDidReset(self)\n    }\n    \n    @objc func rotatePressed(sender: UIButton) {\n        cropView.rotateImageNinetyDegreesAnimated(true)\n    }\n    \n    @objc func donePressed(sender: UIButton) {\n        \n        let cropFrame  = cropView.imageCropFrame\n        let angle      = cropView.angle\n        let editedImage: CLDWidgetAssetContainer = image\n        \n        // check if image edited\n        if angle != 0 || !cropFrame.equalTo(CGRect(origin: CGPoint.zero, size: image.editedImage!.size)) {\n            let newImage = image.editedImage?.cld_cropImage(to: cropFrame, angle: angle)\n            editedImage.editedImage = newImage\n            \n            if let presentationImage = newImage {\n                editedImage.presentationImage = presentationImage\n            }\n        }\n        \n        delegate?.widgetEditViewController(self, didFinishEditing: editedImage)\n    }\n}\n\nextension UIImage {\n    \n    func cld_hasAlpha() -> Bool {\n        \n        guard let cgimage = self.cgImage else { return false }\n        let alphaInfo = cgimage.alphaInfo\n        return (alphaInfo == .first || alphaInfo == .last ||\n                    alphaInfo == .premultipliedFirst || alphaInfo == .premultipliedLast)\n    }\n    \n    func cld_cropImage(to frame: CGRect, angle: NSInteger) -> UIImage {\n        \n        var croppedImage: UIImage?\n        \n        UIGraphicsBeginImageContextWithOptions(frame.size, !cld_hasAlpha(), scale)\n        \n        let context = UIGraphicsGetCurrentContext()\n        \n        //To conserve memory in not needing to completely re-render the image re-rotated,\n        //map the image to a view and then use Core Animation to manipulate its rotation\n        if (angle != 0) {\n            let imageView = UIImageView(image: self)\n            imageView.layer.minificationFilter  = .nearest\n            imageView.layer.magnificationFilter = .nearest\n            imageView.transform = CGAffineTransform.identity.rotated(by: CGFloat(angle) * (CGFloat(Double.pi)/180.0))\n            \n            let rotatedRect = imageView.bounds.applying(imageView.transform)\n            let containerView = UIView(frame: CGRect(origin: .zero, size: rotatedRect.size))\n            containerView.addSubview(imageView)\n            imageView.center = containerView.center\n            context?.translateBy(x: -frame.origin.x, y: -frame.origin.y)\n            \n            containerView.layer.render(in: context!)\n        }\n        else {\n            context?.translateBy(x: -frame.origin.x, y: -frame.origin.y)\n            draw(at: .zero)\n        }\n        \n        croppedImage = UIGraphicsGetImageFromCurrentImageContext()\n        \n        UIGraphicsEndImageContext()\n        \n        if let croppedCGImage = croppedImage?.cgImage {\n            return UIImage(cgImage:croppedCGImage , scale: scale, orientation: .up)\n        }\n        else {\n            return self\n        }\n    }\n}\n\n// MARK: - create UI\nprivate extension CLDWidgetEditViewController {\n    \n    var buttonsViewHeight: CGFloat { return 70 }\n    \n    // MARK: - methods\n    func createUI() {\n        \n        view.backgroundColor = .black\n        \n        createAllSubviews()\n        addAllSubviews()\n        addAllConstraints()\n        configureScreen()\n    }\n    \n    func createCropView(for image: UIImage, aspectLockState: Bool) -> CLDCropView {\n        let aView                    = CLDCropView(image: image)\n        aView.autoresizingMask       = [.flexibleWidth, .flexibleHeight]\n        aView.aspectRatioLockEnabled = aspectLockState\n        return aView\n    }\n    \n    func createAllSubviews() {\n        \n        buttonsView = UIView()\n        \n        cropView = createCropView(for: image.editedImage!, aspectLockState: initialAspectLockState == .enabledAndOn)\n        \n        cancelButton = UIButton(type: .custom)\n        cancelButton.setTitle(\"Reset\", for: .normal)\n        cancelButton.addTarget(self, action: #selector(resetPressed), for: .touchUpInside)\n        \n        let buttonImage = CLDImageGenerator.generateImage(from: RotateIconInstructions())\n        rotateButton = UIButton(type: .custom)\n        rotateButton.accessibilityIdentifier = \"editViewControllerRotateButton\"\n        rotateButton.setImage(buttonImage, for: .normal)\n        rotateButton.addTarget(self, action: #selector(rotatePressed), for: .touchUpInside)\n        \n        doneButton   = UIButton(type: .custom)\n        doneButton.setTitle(\"Done\", for: .normal)\n        doneButton.addTarget(self, action: #selector(donePressed), for: .touchUpInside)\n    }\n    \n    func adjustCropViewLocation(_ aView: CLDCropView) {\n        \n        aView.frame = frameForCropView()\n        aView.cropRegionInsets = UIEdgeInsets.zero\n        aView.moveCroppedContentToCenterAnimated(false)\n    }\n    \n    func addAllSubviews() {\n        \n        view.addSubview(cropView)\n        view.addSubview(buttonsView)\n        buttonsView.addSubview(cancelButton)\n        buttonsView.addSubview(rotateButton)\n        buttonsView.addSubview(doneButton)\n    }\n    \n    func addAllConstraints() {\n        \n        buttonsView .translatesAutoresizingMaskIntoConstraints = false\n        cancelButton.translatesAutoresizingMaskIntoConstraints = false\n        rotateButton.translatesAutoresizingMaskIntoConstraints = false\n        doneButton  .translatesAutoresizingMaskIntoConstraints = false\n        \n        var buttonsViewConstraints = [\n            NSLayoutConstraint(item: buttonsView!, attribute: .leading  , relatedBy: .equal, toItem: view, attribute: .leading , multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: buttonsView!, attribute: .trailing , relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0),\n        ]\n        let bottomConstraint: NSLayoutConstraint\n        if #available(iOS 11.0, *) {\n            bottomConstraint = buttonsView!.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -bottomButtonsViewPadding)\n        } else {\n            bottomConstraint = NSLayoutConstraint(item: buttonsView!, attribute: .bottom   , relatedBy: .equal, toItem: bottomLayoutGuide, attribute: .top, multiplier: 1, constant: -bottomButtonsViewPadding)\n        }\n        buttonsViewConstraints.append(bottomConstraint)\n        buttonsViewConstraints.append(NSLayoutConstraint(item: buttonsView!,\n                                                         attribute: .height        , relatedBy: .equal, toItem: nil,\n                                                         attribute: .notAnAttribute, multiplier: 1, constant: buttonsViewHeight))\n        NSLayoutConstraint.activate(buttonsViewConstraints)\n        \n        let cancelButtonConstraints = [\n            NSLayoutConstraint(item: cancelButton!, attribute: .leading , relatedBy: .equal, toItem: buttonsView , attribute: .leading, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: cancelButton!, attribute: .trailing, relatedBy: .equal, toItem: rotateButton, attribute: .leading, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: cancelButton!, attribute: .top     , relatedBy: .equal, toItem: buttonsView , attribute: .top    , multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: cancelButton!, attribute: .bottom  , relatedBy: .equal, toItem: buttonsView , attribute: .bottom , multiplier: 1, constant: 0)\n        ]\n        NSLayoutConstraint.activate(cancelButtonConstraints)\n        \n        let rotateButtonConstraints = [\n            NSLayoutConstraint(item: rotateButton!, attribute: .trailing, relatedBy: .equal, toItem: doneButton  , attribute: .leading, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: rotateButton!, attribute: .top     , relatedBy: .equal, toItem: buttonsView , attribute: .top    , multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: rotateButton!, attribute: .height  , relatedBy: .equal, toItem: cancelButton, attribute: .height , multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: rotateButton!, attribute: .width   , relatedBy: .equal, toItem: cancelButton, attribute: .width  , multiplier: 1, constant: 0)\n        ]\n        NSLayoutConstraint.activate(rotateButtonConstraints)\n        \n        let doneButtonConstraints = [\n            NSLayoutConstraint(item: doneButton!, attribute: .trailing, relatedBy: .equal, toItem: buttonsView , attribute: .trailing, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: doneButton!, attribute: .top     , relatedBy: .equal, toItem: buttonsView , attribute: .top     , multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: doneButton!, attribute: .height  , relatedBy: .equal, toItem: cancelButton, attribute: .height  , multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: doneButton!, attribute: .width   , relatedBy: .equal, toItem: cancelButton, attribute: .width   , multiplier: 1, constant: 0)\n        ]\n        NSLayoutConstraint.activate(doneButtonConstraints)\n    }\n    \n    func configureScreen() {\n        \n        guard let configuration = configuration else { return }\n        \n        if !configuration.allowRotate {\n            rotateButton.isEnabled = false\n            rotateButton.isHidden = true\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetViewControllers/CLDWidgetPreviewViewController.swift",
    "content": "//\n//  CLDWidgetPreviewViewController.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\nimport AVKit\n\nprotocol CLDWidgetPreviewDelegate: AnyObject {\n    \n    func widgetPreviewViewController(_ controller: CLDWidgetPreviewViewController, didFinishEditing assets: [CLDWidgetAssetContainer])\n    func widgetPreviewViewController(_ controller: CLDWidgetPreviewViewController, didSelect asset: CLDWidgetAssetContainer)\n    func widgetPreviewViewControllerDidCancel(_ controller: CLDWidgetPreviewViewController)\n}\n\nclass CLDWidgetPreviewViewController: UIViewController {\n\n    private(set)  var collectionView: UICollectionView!\n    private(set)  var mainImageView : UIImageView!\n    private(set)  var uploadButton  : UIButton!\n    \n    private(set)  var videoView     : CLDVideoView!\n    \n    private(set)  var assets        : [CLDWidgetAssetContainer]\n    internal weak var delegate      : CLDWidgetPreviewDelegate?\n    private(set)  var selectedIndex : Int\n        \n    // MARK: - init\n    init(assets: [CLDWidgetAssetContainer], delegate: CLDWidgetPreviewDelegate? = nil) {\n        \n        self.assets        = assets\n        self.delegate      = delegate\n        self.selectedIndex = 0\n        \n        super.init(nibName: nil, bundle: nil)\n        \n        modalPresentationStyle = .fullScreen\n    }\n    \n    required init?(coder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    override func loadView() {\n        \n        super.loadView()\n        createUI()\n    }\n    \n    func selectedImageEdited(newImage: CLDWidgetAssetContainer) {\n        \n        assets[selectedIndex] = newImage\n        collectionView.reloadItems(at: [IndexPath(row: selectedIndex, section: 0)])\n        mainImageView.image = newImage.editedImage\n    }\n    \n    func selectedImage() -> CLDWidgetAssetContainer {\n        return assets[selectedIndex]\n    }\n    \n    // MARK: - action\n    @objc private func uploadPressed(sender: UIButton) {\n        delegate?.widgetPreviewViewController(self, didFinishEditing: assets)\n    }\n}\n\n// MARK: - UICollectionViewDataSource\nextension CLDWidgetPreviewViewController: UICollectionViewDataSource {\n    \n    func numberOfSections(in collectionView: UICollectionView) -> Int {\n        return 1\n    }\n\n    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {\n        return assets.count\n    }\n\n    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {\n        \n        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! CLDWidgetPreviewCollectionCell\n\n        cell.imageView.image = assets[indexPath.row].presentationImage\n\n        return cell\n    }\n}\n\n// MARK: - UICollectionViewDelegate\nextension CLDWidgetPreviewViewController: UICollectionViewDelegate {\n    \n    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {\n        \n        guard selectedIndex != indexPath.row else { return }\n         \n        selectedIndex = indexPath.row\n        let selectedAsset = assets[selectedIndex]\n        \n        switch selectedAsset.assetType {\n        case .video: videoSelected(video: selectedAsset.originalVideo!)\n        case .image: imageSelected(image: selectedAsset.editedImage!)\n        }\n        \n        delegate?.widgetPreviewViewController(self, didSelect: selectedAsset)\n    }\n}\n\n// MARK: - present asset\nextension CLDWidgetPreviewViewController {\n    \n    var videoTransitionDelay   : TimeInterval { 0.1 }\n    var videoTransitionDuration: TimeInterval { 0.2 }\n    \n    func videoSelected(video: AVPlayerItem) {\n        \n        UIView.animate(withDuration: videoTransitionDuration, animations: {\n            \n            self.videoView.alpha     = 0.0\n            self.mainImageView.alpha = 0.0\n            \n        }) { (complete) in\n                \n            self.videoView.replaceCurrentItem(with: video)\n            \n            UIView.animate(withDuration: self.videoTransitionDuration, delay: self.videoTransitionDelay, options: .curveEaseInOut, animations: {\n                self.videoView.alpha = 1\n                \n            }, completion: nil)\n        }\n    }\n    \n    func imageSelected(image: UIImage) {\n        \n        videoView.pauseVideo()\n        \n        mainImageView.image = image\n        \n        showImageView()\n    }\n    \n    func showVideoView() {\n        \n        UIView.animate(withDuration: 0.4) {\n            self.videoView.alpha = 1.0\n            self.mainImageView.alpha = 0.0\n        }\n    }\n    \n    func showImageView() {\n        \n        UIView.animate(withDuration: 0.4) {\n            self.videoView.alpha = 0.0\n            self.mainImageView.alpha = 1.0\n        }\n    }\n}\n\n// MARK: - create UI\nprivate extension CLDWidgetPreviewViewController {\n    \n    var cellId               : String       { return \"CLDWidgetPreviewCollectionCell\" }\n    \n    var collectionCellSpacing: CGFloat      { return 2 }\n    var collectionHeight     : CGFloat      { return 70 }\n    var buttonSize           : CGSize       { return CGSize(width: 80, height: 80) }\n    var sectionInsets        : UIEdgeInsets { return UIEdgeInsets(top: 0.0, left: 5.0, bottom: 0.0, right: 5.0) }\n    var collectionCellSize   : CGSize       { return CGSize(width: collectionHeight * 0.9, height: collectionHeight) }\n    \n    // MARK: - private methods\n    func createUI() {\n        \n        view.backgroundColor = .black\n        \n        createAllSubviews()\n        addAllSubviews()\n        addAllConstraints()\n        \n        // initial asset presentation state\n        switch assets[0].assetType {\n        case .video: mainImageView.alpha = 0\n        case .image: videoView.alpha     = 0\n        }\n    }\n\n    func createAllSubviews() {\n        \n        // collectionView\n        let layout                     = UICollectionViewFlowLayout()\n        layout.sectionInset            = sectionInsets\n        layout.minimumLineSpacing      = collectionCellSpacing\n        layout.minimumInteritemSpacing = collectionCellSpacing\n        \n        layout.itemSize                = collectionCellSize\n        layout.scrollDirection         = .horizontal\n        \n        collectionView                         = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)\n        collectionView.allowsSelection         = true\n        collectionView.allowsMultipleSelection = false\n        \n        collectionView.delegate   = self\n        collectionView.dataSource = self\n        \n        collectionView.register(CLDWidgetPreviewCollectionCell.self, forCellWithReuseIdentifier: cellId)\n        \n        // imageView\n        mainImageView             = UIImageView(image: assets[0].editedImage)\n        mainImageView.contentMode = .scaleAspectFit\n        \n        // videoView\n        let playerItem                    = assets[0].originalVideo\n        videoView                         = CLDVideoView(frame: CGRect.zero, playerItem: playerItem, isMuted: true)\n        videoView.accessibilityIdentifier = \"previewViewControllerVideoView\"\n        \n        // upload button\n        let buttonImage = CLDImageGenerator.generateImage(from: DoneIconInstructions())\n        uploadButton = UIButton(type: .custom)\n        uploadButton.setTitle(String(), for: .normal)\n        uploadButton.setImage(buttonImage, for: .normal)\n        uploadButton.addTarget(self, action: #selector(uploadPressed), for: .touchUpInside)\n    }\n    \n    func addAllSubviews() {\n        \n        view.addSubview(mainImageView)\n        view.addSubview(collectionView)\n        view.addSubview(videoView)\n        view.addSubview(uploadButton)\n    }\n    \n    func addAllConstraints() {\n        \n        mainImageView .translatesAutoresizingMaskIntoConstraints = false\n        collectionView.translatesAutoresizingMaskIntoConstraints = false\n        uploadButton  .translatesAutoresizingMaskIntoConstraints = false\n        videoView     .translatesAutoresizingMaskIntoConstraints = false\n        \n        // collectionView\n        var collectionConstraints = [\n            NSLayoutConstraint(item: collectionView!, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: collectionView!, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: collectionView!, attribute: .top, relatedBy: .equal, toItem: mainImageView, attribute: .bottom, multiplier: 1, constant: 5)\n        ]\n        \n        let bottomConstraint: NSLayoutConstraint\n        if #available(iOS 11.0, *) {\n            bottomConstraint = collectionView!.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10)\n        } else {\n            bottomConstraint = NSLayoutConstraint(item: collectionView!, attribute: .bottom   , relatedBy: .equal, toItem: bottomLayoutGuide, attribute: .top, multiplier: 1, constant: -10)\n        }\n        collectionConstraints.append(bottomConstraint)\n        collectionConstraints.append(NSLayoutConstraint(item: collectionView!,\n                                                        attribute: .height        , relatedBy : .equal, toItem: nil,\n                                                        attribute: .notAnAttribute, multiplier: 1, constant: collectionHeight))\n        NSLayoutConstraint.activate(collectionConstraints)\n        \n        // imageView\n        var imageViewConstraints = [\n            NSLayoutConstraint(item: mainImageView!, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: mainImageView!, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0),\n        ]\n        if #available(iOS 11.0, *) {\n            imageViewConstraints.append(mainImageView!.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0))\n        } else {\n            imageViewConstraints.append(NSLayoutConstraint(item: mainImageView!,\n                                                           attribute: .top   , relatedBy: .equal, toItem: topLayoutGuide,\n                                                           attribute: .bottom, multiplier: 1, constant: 0))\n        }\n        NSLayoutConstraint.activate(imageViewConstraints)\n        \n        // videoView\n        let videoViewConstraints = [\n            NSLayoutConstraint(item: videoView!, attribute: .leading , relatedBy: .equal, toItem: mainImageView, attribute: .leading , multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: videoView!, attribute: .trailing, relatedBy: .equal, toItem: mainImageView, attribute: .trailing, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: videoView!, attribute: .top     , relatedBy: .equal, toItem: mainImageView, attribute: .top     , multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: videoView!, attribute: .bottom  , relatedBy: .equal, toItem: mainImageView, attribute: .bottom  , multiplier: 1, constant: 0)\n        ]\n        NSLayoutConstraint.activate(videoViewConstraints)\n        \n        // uploadButton\n        let uploadButtonConstraints = [\n            NSLayoutConstraint(item: uploadButton!, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing       , multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: uploadButton!, attribute: .width   , relatedBy: .equal, toItem: nil , attribute: .notAnAttribute , multiplier: 1, constant: buttonSize.width),\n            NSLayoutConstraint(item: uploadButton!, attribute: .height  , relatedBy: .equal, toItem: nil , attribute: .notAnAttribute , multiplier: 1, constant: buttonSize.height),\n            NSLayoutConstraint(item: uploadButton!, attribute: .bottom  , relatedBy: .equal, toItem: mainImageView, attribute: .bottom, multiplier: 1, constant: 0)\n        ]\n        NSLayoutConstraint.activate(uploadButtonConstraints)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/UploadWidget/WidgetViewControllers/CLDWidgetViewController.swift",
    "content": "//\n//  CLDWidgetViewController.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\ninternal protocol CLDWidgetViewControllerDelegate: AnyObject {\n    func widgetViewController(_ controller: CLDWidgetViewController, didFinishEditing editedAssets: [CLDWidgetAssetContainer])\n    func widgetViewControllerDidCancel(_ controller: CLDWidgetViewController)\n}\n\ninternal class CLDWidgetViewController: UIViewController {\n    \n    private(set)  var configuration        : CLDWidgetConfiguration?\n    private(set)  var assets               : [CLDWidgetAssetContainer]\n    internal weak var delegate             : CLDWidgetViewControllerDelegate?\n    \n    private(set) var topButtonsView        : UIView!\n    private(set) var backButton            : UIButton!\n    private(set) var actionButton          : UIButton!\n    private(set) var containerView         : UIView!\n    \n    private(set) var previewViewController : CLDWidgetPreviewViewController!\n    private(set) var editViewController    : CLDWidgetEditViewController!\n    private(set) var editIsPresented       : Bool\n    \n    private      var currentAspectLockState: CLDWidgetConfiguration.AspectRatioLockState\n\n    private lazy var previewActionButtonTitle      = NSAttributedString(string: \"edit \", withSuffix: CLDImageGenerator.generateImage(from: CropRotateIconInstructions()))\n    private lazy var editActionButtonLockedTitle   = NSAttributedString(string: \"Aspect ratio locked \", withSuffix: CLDImageGenerator.generateImage(from: RatioLockedIconInstructions()))\n    private lazy var editActionButtonUnlockedTitle = NSAttributedString(string: \"Aspect ratio unlocked \", withSuffix: CLDImageGenerator.generateImage(from: RatioOpenedIconInstructions()))\n    private lazy var editActionButtonEmptyTitle    = NSAttributedString(string: String())\n    private lazy var transitionDuration            = 0.5\n        \n    // MARK: - init\n    internal init(\n        assets       : [CLDWidgetAssetContainer],\n        configuration: CLDWidgetConfiguration? = nil,\n        delegate     : CLDWidgetViewControllerDelegate? = nil\n    ) {\n        \n        self.configuration = configuration\n        self.assets        = assets\n        self.delegate      = delegate\n        self.editIsPresented        = false\n        self.currentAspectLockState = .enabledAndOff\n        \n        super.init(nibName: nil, bundle: nil)\n        \n        if let initialAspectLockState = configuration?.initialAspectLockState {\n            currentAspectLockState = initialAspectLockState\n        }\n        \n        previewViewController = CLDWidgetPreviewViewController(assets: assets, delegate: self)\n    }\n    \n    required init?(coder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n    \n    override func loadView() {\n        super.loadView()\n        createUI()\n    }\n}\n\n// MARK: - private methods\nprivate extension CLDWidgetViewController {\n\n    func moveToPreviewScreen() {\n        \n        editIsPresented = false\n        \n        transition(from: editViewController, to: previewViewController, inView: containerView)\n        \n        updateActionButton(by: .goToEditScreen)\n    }\n    \n    func moveToEditScreen(with image: CLDWidgetAssetContainer) {\n        \n        editIsPresented = true\n        \n        editViewController = nil\n        editViewController = CLDWidgetEditViewController(image: image, configuration: configuration, delegate: self, initialAspectLockState: currentAspectLockState)\n        \n        transition(from: previewViewController, to: editViewController, inView: containerView)\n        \n        updateActionButton(by: currentAspectLockState)\n    }\n}\n\n// MARK: - CLDWidgetPreviewDelegate\nextension CLDWidgetViewController: CLDWidgetPreviewDelegate {\n    \n    func widgetPreviewViewController(_ controller: CLDWidgetPreviewViewController, didFinishEditing assets: [CLDWidgetAssetContainer]) {\n        delegate?.widgetViewController(self, didFinishEditing: assets)\n    }\n    \n    func widgetPreviewViewControllerDidCancel(_ controller: CLDWidgetPreviewViewController) {\n        delegate?.widgetViewControllerDidCancel(self)\n    }\n    \n    func widgetPreviewViewController(_ controller: CLDWidgetPreviewViewController, didSelect asset: CLDWidgetAssetContainer) {\n        changeActionButtonState(by: asset)\n    }\n    \n    func changeActionButtonState(by asset: CLDWidgetAssetContainer) {\n        asset.assetType == .image ? updateActionButton(by: .goToEditScreen) : updateActionButton(by: .goToEditScreenDisabled)\n    }\n}\n\n// MARK: - CLDWidgetEditDelegate\nextension CLDWidgetViewController: CLDWidgetEditDelegate {\n    \n    func widgetEditViewController(_ controller: CLDWidgetEditViewController, didFinishEditing image: CLDWidgetAssetContainer) {\n        \n        previewViewController.selectedImageEdited(newImage: image)\n        moveToPreviewScreen()\n    }\n    \n    func widgetEditViewControllerDidReset(_ controller: CLDWidgetEditViewController) {\n        if currentAspectLockState != .disabled {\n            currentAspectLockState = .enabledAndOff\n            updateActionButton(by: .enabledAndOff)\n        }\n    }\n    \n    func widgetEditViewControllerDidCancel(_ controller: CLDWidgetEditViewController) {\n        moveToPreviewScreen()\n    }\n}\n\n// MARK: - child presentation\nprivate extension CLDWidgetViewController {\n    \n    func transition(from oldViewController: UIViewController, to newViewController: UIViewController, inView containerView: UIView) {\n        \n        // invoke viewWillAppear()...\n        newViewController.beginAppearanceTransition(true, animated: true)\n        oldViewController.beginAppearanceTransition(false, animated: true)\n        \n        // check if its already self child\n        if newViewController.parent != self {\n            \n            addChild(newViewController)\n            newViewController.didMove(toParent: self)\n        }\n        \n        // adding newVC.view to fill containerView\n        newViewController.view.removeFromSuperview()\n        containerView.addSubview(newViewController.view)\n        newViewController.view.cld_addConstraintsToFill(containerView)\n        \n        // prepare for animation\n        newViewController.view.alpha = 0\n        containerView.bringSubviewToFront(newViewController.view)\n        newViewController.view.layoutIfNeeded()\n        \n        // animate\n        UIView.animate(withDuration: transitionDuration, delay: 0, options: [], animations: {\n            \n            newViewController.view.alpha = 1\n            oldViewController.view.alpha = 0\n            \n        }) { (complete) in\n            \n            newViewController.endAppearanceTransition()\n            oldViewController.endAppearanceTransition()\n            oldViewController.view.removeFromSuperview()\n        }\n    }\n    \n    func presentAsChild(_ viewController: UIViewController, inView containerView: UIView) {\n        \n        viewController.beginAppearanceTransition(true, animated: true)\n        \n        if viewController.parent != self {\n            \n            addChild(viewController)\n            viewController.didMove(toParent: self)\n        }\n        \n        viewController.view.removeFromSuperview()\n        \n        containerView.addSubview(viewController.view)\n        viewController.view.cld_addConstraintsToFill(containerView)\n        \n        containerView.bringSubviewToFront(viewController.view)\n        viewController.view.layoutIfNeeded()\n        \n        viewController.endAppearanceTransition()\n    }\n}\n\n// MARK: - top buttons\nprivate extension CLDWidgetViewController {\n    \n    enum ActionButtonState: Int {\n        case aspectRatioEnabledAndOff\n        case aspectRatioEnabledAndOn\n        case aspectRatioDisabled\n        case goToEditScreen\n        case goToEditScreenDisabled\n    }\n    \n    @objc func actionPressed(_ sender: UIButton) {\n        if editIsPresented {\n            toggleAspectRatioLockStates()\n            editViewController.aspectRatioLockPressed()\n        }\n        else {\n            moveToEditScreen(with: previewViewController.selectedImage())\n        }\n    }\n    \n    @objc func backPressed(_ sender: UIButton) {\n        if editIsPresented {\n            moveToPreviewScreen()\n        }\n        else {\n            delegate?.widgetViewControllerDidCancel(self)\n        }\n    }\n    \n    func toggleAspectRatioLockStates() {\n        currentAspectLockState = currentAspectLockState == .enabledAndOff ? .enabledAndOn : .enabledAndOff\n        updateActionButton(by: currentAspectLockState)\n    }\n    \n    func updateActionButton(by aspectLockState: CLDWidgetConfiguration.AspectRatioLockState) {\n       \n        switch aspectLockState {\n        case .enabledAndOff: updateActionButton(by: .aspectRatioEnabledAndOff)\n        case .enabledAndOn : updateActionButton(by: .aspectRatioEnabledAndOn)\n        case .disabled     : updateActionButton(by: .aspectRatioDisabled)\n        }\n    }\n    \n    func updateActionButton(by actionButtonState: ActionButtonState) {\n        \n        UIView.transition(with: actionButton, duration: transitionDuration, options: .transitionCrossDissolve, animations: {\n            switch actionButtonState {\n            \n            case .aspectRatioEnabledAndOff:\n                self.actionButton.setAttributedTitle(self.editActionButtonUnlockedTitle, for: .normal)\n                \n            case .aspectRatioEnabledAndOn:\n                self.actionButton.setAttributedTitle(self.editActionButtonLockedTitle,   for: .normal)\n                \n            case .aspectRatioDisabled   : fallthrough\n            case .goToEditScreenDisabled:\n                self.actionButton.setAttributedTitle(self.editActionButtonEmptyTitle,    for: .normal)\n                self.actionButton.isEnabled = false\n                \n            case .goToEditScreen:\n                self.setActionButtonToGoToEdit()\n            }\n        }, completion: nil)\n    }\n    \n    func setActionButtonToGoToEdit() {\n        self.actionButton.setAttributedTitle(previewActionButtonTitle, for: .normal)\n        self.actionButton.isEnabled = true\n    }\n}\n\n// MARK: - create UI\nprivate extension CLDWidgetViewController {\n    \n    var topButtonsViewHeight: CGFloat { return 44 }\n    var backButtonWidthRatio: CGFloat { return 0.25 }\n    \n    func createUI() {\n        \n        view.backgroundColor = .black\n        \n        createAllSubviews()\n        addAllSubviews()\n        addAllConstraints()\n        \n        presentAsChild(previewViewController, inView: containerView)\n    }\n    \n    func createAllSubviews() {\n        \n        // top buttons view\n        topButtonsView = UIView(frame: CGRect.zero)\n        \n        // buttons\n        let buttonImage = CLDImageGenerator.generateImage(from: BackIconInstructions())\n        backButton = UIButton(type: .custom)\n        backButton.setImage(buttonImage, for: .normal)\n        backButton.contentHorizontalAlignment = .left\n        backButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 0)\n        backButton.addTarget(self, action: #selector(backPressed), for: .touchUpInside)\n        \n        actionButton = UIButton(type: .custom)\n        actionButton.accessibilityIdentifier = \"widgetViewControllerActionButton\"\n        changeActionButtonState(by: assets[0])\n        actionButton.contentHorizontalAlignment = .right\n        actionButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 15)\n        actionButton.addTarget(self, action: #selector(actionPressed), for: .touchUpInside)\n        \n        // container view\n        containerView = UIView(frame: CGRect.zero)\n    }\n    \n    func addAllSubviews() {\n        \n        view.addSubview(topButtonsView)\n        topButtonsView.addSubview(backButton)\n        topButtonsView.addSubview(actionButton)\n        view.addSubview(containerView)\n    }\n    \n    func addAllConstraints() {\n        \n        topButtonsView.translatesAutoresizingMaskIntoConstraints = false\n        backButton    .translatesAutoresizingMaskIntoConstraints = false\n        actionButton  .translatesAutoresizingMaskIntoConstraints = false\n        containerView .translatesAutoresizingMaskIntoConstraints = false\n        \n        // top buttons view\n        var collectionConstraints = [\n            NSLayoutConstraint(item: topButtonsView!, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: topButtonsView!, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0),\n        ]\n        if #available(iOS 11.0, *) {\n            collectionConstraints.append(topButtonsView!.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0))\n        } else {\n            collectionConstraints.append(NSLayoutConstraint(item: topButtonsView!,\n                                                            attribute: .top   , relatedBy: .equal, toItem: topLayoutGuide,\n                                                            attribute: .bottom, multiplier: 1, constant: 0))\n        }\n        collectionConstraints.append(NSLayoutConstraint(item: topButtonsView!,\n                                                        attribute: .height        , relatedBy: .equal, toItem: nil,\n                                                        attribute: .notAnAttribute, multiplier: 1, constant: topButtonsViewHeight))\n        \n        NSLayoutConstraint.activate(collectionConstraints)\n        \n        // buttons\n        let backButtonConstraints = [\n            NSLayoutConstraint(item: backButton!, attribute: .leading, relatedBy: .equal, toItem: topButtonsView, attribute: .leading, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: backButton!, attribute: .top, relatedBy: .equal, toItem: topButtonsView, attribute: .top, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: backButton!, attribute: .bottom, relatedBy: .equal, toItem: topButtonsView, attribute: .bottom, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: backButton!, attribute: .width\n                , relatedBy: .equal, toItem: topButtonsView, attribute: .width, multiplier: backButtonWidthRatio, constant: 0)\n        ]\n        NSLayoutConstraint.activate(backButtonConstraints)\n        \n        backButton.setContentHuggingPriority(.defaultHigh, for: .horizontal)\n        \n        let actionButtonConstraints = [\n            NSLayoutConstraint(item: actionButton!, attribute: .trailing, relatedBy: .equal, toItem: topButtonsView, attribute: .trailing, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: actionButton!, attribute: .top, relatedBy: .equal, toItem: topButtonsView, attribute: .top, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: actionButton!, attribute: .bottom, relatedBy: .equal, toItem: topButtonsView, attribute: .bottom, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: actionButton!, attribute: .leading, relatedBy: .lessThanOrEqual, toItem: backButton, attribute: .trailing, multiplier: 1, constant: view.frame.width * 0.25),\n        ]\n        NSLayoutConstraint.activate(actionButtonConstraints)\n        \n        // container view\n        var containerViewConstraints = [\n            NSLayoutConstraint(item: containerView!, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: containerView!, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: containerView!, attribute: .top, relatedBy: .equal, toItem: topButtonsView, attribute: .bottom, multiplier: 1, constant: 0),\n        ]\n        \n        if #available(iOS 11.0, *) {\n            containerViewConstraints.append(containerView!.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0))\n        } else {\n            containerViewConstraints.append(NSLayoutConstraint(item: containerView!,\n                                                               attribute: .bottom, relatedBy : .equal, toItem: bottomLayoutGuide,\n                                                               attribute: .top   , multiplier: 1, constant: 0))\n        }\n        NSLayoutConstraint.activate(containerViewConstraints)\n    }\n}\n\n// MARK: - extension UIView\nextension UIView {\n    \n    func cld_addConstraintsToFill(_ parentView: UIView) {\n        \n        translatesAutoresizingMaskIntoConstraints = false\n        \n        let constraints = [\n            NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: parentView, attribute: .leading, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal, toItem: parentView, attribute: .trailing, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: parentView, attribute: .top, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: parentView, attribute: .bottom, multiplier: 1, constant: 0)\n        ]\n        NSLayoutConstraint.activate(constraints)\n    }\n    \n    func cld_addConstraintsToCenter(_ parentView: UIView) {\n        \n        translatesAutoresizingMaskIntoConstraints = false\n        \n        let constraints = [\n            NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 80),\n            NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 80),\n            NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: parentView, attribute: .centerX, multiplier: 1, constant: 0),\n            NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: parentView, attribute: .centerY, multiplier: 1, constant: 0),\n        ]\n        NSLayoutConstraint.activate(constraints)\n    }\n}\n\n// MARK: - extension NSAttributedString\nprivate extension NSAttributedString {\n        \n    convenience init(string: String, color: UIColor = .white, withSuffix image: UIImage? = nil) {\n        \n        if let image = image {\n           \n            // Create Attachment\n            let imageAttachment   = NSTextAttachment()\n            imageAttachment.image = image\n            \n            // Set bound to reposition\n            let imageOffsetY: CGFloat = -5.0\n            imageAttachment.bounds    = CGRect(x: 0, y: imageOffsetY, width: image.size.width, height: image.size.height)\n            \n            // Create string with attachment\n            let attachmentString = NSAttributedString(attachment: imageAttachment)\n            \n            // Initialize mutable string\n            let completeText = NSMutableAttributedString(string: string, attributes: [NSAttributedString.Key.foregroundColor: color])\n            \n            // Add image to mutable string\n            completeText.append(attachmentString)\n            \n            self.init(attributedString: completeText)\n        }\n        else {\n            self.init(string: string)\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Uploader/CLDUploader.swift",
    "content": "//\n//  CLDUploader.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The CLDUploader class is used to upload assets to your Cloudinary account's cloud.\n*/\n@objcMembers open class CLDUploader: CLDBaseNetworkObject {\n    static public let defaultChunkSize = 20 * 1024 * 1024\n    \n    // MARK: - Init\n\n    fileprivate override init() {\n        super.init()\n    }\n\n    internal override init(networkCoordinator: CLDNetworkCoordinator) {\n        super.init(networkCoordinator: networkCoordinator)\n    }\n\n    // MARK: - Actions\n\n    /**\n   Uploads the given data to the configured cloud.\n\n   - parameter data:              The data to upload.\n   - parameter uploadPreset:      The upload preset to use for unsigned upload.\n   - parameter params:            An object holding all the available parameters for uploading.\n   - parameter progress:          The closure that is called periodically during the data transfer.\n   - parameter completionHandler: The closure to be called once the request has finished, holding either the response object or the error.\n\n   - returns:                     An instance implementing the protocol `CLDNetworkDataRequest`,\n                                  allowing the options to add a progress closure that is called periodically during the upload\n                                  and a response closure to be called once the upload is finished,\n                                  as well as performing actions on the request, such as cancelling, suspending or resuming it.\n   */\n    @discardableResult\n    open func upload(data: Data, uploadPreset: String, params: CLDUploadRequestParams? = nil, progress: ((Progress) -> Void)? = nil, completionHandler:((_ response: CLDUploadResult?, _ error: NSError?) -> ())? = nil) -> CLDUploadRequest {\n        let params = params ?? CLDUploadRequestParams()\n        params.setSigned(false)\n        params.setUploadPreset(uploadPreset)\n        return performUpload(data: data, params: params, preprocessChain: CLDPreprocessChain<Any>(), progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\n   Uploads the given data to the configured cloud.\n\n   - parameter data:              The data to upload.\n   - parameter uploadPreset:      The upload preset to use for unsigned upload.\n   - parameter params:            An object holding all the available parameters for uploading.\n   - parameter preprocessChain    A CLDPreprocessing chain containing processing steps and/or custom encoder to run on the resource before uploading\n   - parameter progress:          The closure that is called periodically during the data transfer.\n   - parameter completionHandler: The closure to be called once the request has finished, holding either the response object or the error.\n\n   - returns:                     An instance implementing the protocol `CLDNetworkDataRequest`,\n                                  allowing the options to add a progress closure that is called periodically during the upload\n                                  and a response closure to be called once the upload is finished,\n                                  as well as performing actions on the request, such as cancelling, suspending or resuming it.\n   */\n    @discardableResult\n    open func upload<T>(data: Data, uploadPreset: String, params: CLDUploadRequestParams? = nil, preprocessChain:CLDPreprocessChain<T>, progress: ((Progress) -> Void)? = nil, completionHandler:((_ response: CLDUploadResult?, _ error: NSError?) -> ())? = nil) -> CLDUploadRequest {\n        let params = params ?? CLDUploadRequestParams()\n        params.setSigned(false)\n        params.setUploadPreset(uploadPreset)\n        return performUpload(data: data, params: params, preprocessChain: preprocessChain, progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\n Uploads a file from the specified URL to the configured cloud.\n The URL can either be of a local file (i.e. from the bundle) or can point to a remote file.\n\n - parameter url:               The URL pointing to the file to upload.\n - parameter uploadPreset:      The upload preset to use for unsigned upload.\n - parameter params:            An object holding all the available parameters for uploading.\n - parameter progress:          The closure that is called periodically during the data transfer.\n - parameter completionHandler: The closure to be called once the request has finished, holding either the response object or the error.\n\n - returns:                     An instance implementing the protocol `CLDNetworkDataRequest`,\n                                allowing the options to add a progress closure that is called periodically during the upload\n                                and a response closure to be called once the upload is finished,\n                                as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n    @discardableResult\n    open func upload(url: URL, uploadPreset: String, params: CLDUploadRequestParams? = nil, progress: ((Progress) -> Void)? = nil, completionHandler:((_ response: CLDUploadResult?, _ error: NSError?) -> ())? = nil) -> CLDUploadRequest {\n        let params = params ?? CLDUploadRequestParams()\n        params.setSigned(false)\n        params.setUploadPreset(uploadPreset)\n        return performUpload(data: url, params: params, preprocessChain: CLDPreprocessChain<Any>(), progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\nUploads a file from the specified URL to the configured cloud.\nThe URL can either be of a local file (i.e. from the bundle) or can point to a remote file.\n\n- parameter url:               The URL pointing to the file to upload.\n- parameter uploadPreset:      The upload preset to use for unsigned upload.\n- parameter params:            An object holding all the available parameters for uploading.\n- parameter preprocessChain    A CLDPreprocessing chain containing processing steps and/or custom encoder to run on the resource before uploading\n- parameter progress:          The closure that is called periodically during the data transfer.\n- parameter completionHandler: The closure to be called once the request has finished, holding either the response object or the error.\n\n- returns:                     An instance implementing the protocol `CLDNetworkDataRequest`,\n                               allowing the options to add a progress closure that is called periodically during the upload\n                               and a response closure to be called once the upload is finished,\n                               as well as performing actions on the request, such as cancelling, suspending or resuming it.\n*/\n    @discardableResult\n    open func upload<T>(url: URL, uploadPreset: String, params: CLDUploadRequestParams? = nil, preprocessChain: CLDPreprocessChain<T>, progress: ((Progress) -> Void)? = nil, completionHandler:((_ response: CLDUploadResult?, _ error: NSError?) -> ())? = nil) -> CLDUploadRequest {\n        let params = params ?? CLDUploadRequestParams()\n        params.setSigned(false)\n        params.setUploadPreset(uploadPreset)\n        return performUpload(data: url, params: params, preprocessChain: preprocessChain, progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\n    Uploads the given data to the configured cloud.\n\n    - parameter data:               The data to upload.\n    - parameter params:             An object holding all the available parameters for uploading.\n    - parameter progress:      The closure that is called periodically during the data transfer.\n    - parameter completionHandler:  The closure to be called once the request has finished, holding either the response object or the error.\n\n    - returns:                      An instance implementing the protocol `CLDNetworkDataRequest`,\n                                    allowing the options to add a progress closure that is called periodically during the upload\n                                    and a response closure to be called once the upload is finished,\n                                    as well as performing actions on the request, such as cancelling, suspending or resuming it.\n    */\n    @discardableResult\n    open func signedUpload(data: Data, params: CLDUploadRequestParams? = nil, progress: ((Progress) -> Void)? = nil, completionHandler:((_ response: CLDUploadResult?, _ error: NSError?) -> ())? = nil) -> CLDUploadRequest {\n        let params = params ?? CLDUploadRequestParams()\n        params.setSigned(true)\n        return performUpload(data: data, params: params, preprocessChain: CLDPreprocessChain<Any>(), progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\n    Uploads the given data to the configured cloud.\n\n    - parameter data:               The data to upload.\n    - parameter params:             An object holding all the available parameters for uploading.\n    - parameter preprocessChain     A CLDPreprocessing chain containing processing steps and/or custom encoder to run on the resource before uploading\n    - parameter progress:           The closure that is called periodically during the data transfer.\n    - parameter completionHandler:  The closure to be called once the request has finished, holding either the response object or the error.\n\n    - returns:                      An instance implementing the protocol `CLDNetworkDataRequest`,\n                                    allowing the options to add a progress closure that is called periodically during the upload\n                                    and a response closure to be called once the upload is finished,\n                                    as well as performing actions on the request, such as cancelling, suspending or resuming it.\n    */\n    @discardableResult\n    open func signedUpload<T>(data: Data, params: CLDUploadRequestParams? = nil, preprocessChain:CLDPreprocessChain<T>, progress: ((Progress) -> Void)? = nil, completionHandler:((_ response: CLDUploadResult?, _ error: NSError?) -> ())? = nil) -> CLDUploadRequest {\n        let params = params ?? CLDUploadRequestParams()\n        params.setSigned(true)\n        return performUpload(data: data, params: params, preprocessChain:preprocessChain, progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\n     Uploads a file from the specified URL to the configured cloud.\n     The URL can either be of a local file (i.e. from the bundle) or can point to a remote file.\n     - parameter url:              The URL pointing to the file to upload.\n     - parameter params:            An object holding all the available parameters for uploading.\n     - parameter progress:     The closure that is called periodically during the data transfer.\n     - parameter completionHandler: The closure to be called once the request has finished, holding either the response object or the error.\n     - returns:                     An instance implementing the protocol `CLDNetworkDataRequest`,\n                                    allowing the options to add a progress closure that is called periodically during the upload\n                                    and a response closure to be called once the upload is finished,\n                                    as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func signedUpload(url: URL, params: CLDUploadRequestParams? = nil, progress: ((Progress) -> Void)? = nil, completionHandler:((_ response: CLDUploadResult?, _ error: NSError?) -> ())? = nil) -> CLDUploadRequest {\n        let params = params ?? CLDUploadRequestParams()\n        params.setSigned(true)\n        return performUpload(data: url, params: params, preprocessChain: CLDPreprocessChain<Any>(), progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\n     Uploads a file from the specified URL to the configured cloud.\n     The URL can either be of a local file (i.e. from the bundle) or can point to a remote file.\n     - parameter url:               The URL pointing to the file to upload.\n     - parameter params:            An object holding all the available parameters for uploading.\n     - parameter preprocessChain    A CLDPreprocessing chain containing processing steps and/or custom encoder to run on the resource before uploading\n     - parameter progress:          The closure that is called periodically during the data transfer.\n     - parameter completionHandler: The closure to be called once the request has finished, holding either the response object or the error.\n     - returns:                     An instance implementing the protocol `CLDNetworkDataRequest`,\n                                    allowing the options to add a progress closure that is called periodically during the upload\n                                    and a response closure to be called once the upload is finished,\n                                    as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    @discardableResult\n    open func signedUpload<T>(url: URL, params: CLDUploadRequestParams? = nil, preprocessChain: CLDPreprocessChain<T>, progress: ((Progress) -> Void)? = nil, completionHandler:((_ response: CLDUploadResult?, _ error: NSError?) -> ())? = nil) -> CLDUploadRequest {\n        let params = params ?? CLDUploadRequestParams()\n        params.setSigned(true)\n        return performUpload(data: url, params: params, preprocessChain: preprocessChain, progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\n   Uploads a file in chunks from the specified local-file URL to the configured cloud\n\n   - parameter url:               The URL pointing to the file to upload.\n   - parameter uploadPreset:      The upload preset to use for unsigned upload.\n   - parameter params:            An object holding all the available parameters for uploading.\n   - parameter progress:          The closure that is called periodically during the data transfer.\n   - parameter completionHandler: The closure to be called once the request is prepared, holding either the request object or an error\n   */\n    @discardableResult\n    open func uploadLarge(url: URL, uploadPreset: String, params: CLDUploadRequestParams = CLDUploadRequestParams(), chunkSize: Int = defaultChunkSize, progress: ((Progress) -> Void)? = nil,\n                          completionHandler: CLDUploadCompletionHandler? = nil) -> CLDUploadRequest{\n        params.setSigned(false)\n        params.setUploadPreset(uploadPreset)\n        return performUploadLarge(url: url, params: params, preprocessChain: CLDPreprocessChain<Any>(), chunkSize: chunkSize, progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\n   Uploads a file in chunks from the specified local-file URL to the configured cloud\n\n   - parameter url:               The URL pointing to the file to upload.\n   - parameter uploadPreset:      The upload preset to use for unsigned upload.\n   - parameter params:            An object holding all the available parameters for uploading.\n   - parameter preprocessChain    A CLDPreprocessing chain containing processing steps and/or custom encoder to run on the resource before uploading\n   - parameter progress:          The closure that is called periodically during the data transfer.\n   - parameter completionHandler: The closure to be called once the request is prepared, holding either the request object or an error\n   */\n    @discardableResult\n    open func uploadLarge<T>(url: URL, uploadPreset: String, params: CLDUploadRequestParams = CLDUploadRequestParams(), preprocessChain: CLDPreprocessChain<T>, chunkSize: Int = defaultChunkSize, progress: ((Progress) -> Void)? = nil,\n                          completionHandler: CLDUploadCompletionHandler? = nil) -> CLDUploadRequest{\n        params.setSigned(false)\n        params.setUploadPreset(uploadPreset)\n        return performUploadLarge(url: url, params: params, preprocessChain: preprocessChain, chunkSize: chunkSize, progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\n     Uploads a file in chunks from the specified local-file URL to the configured cloud\n\n     - parameter url:               The URL pointing to the local file to upload.\n     - parameter params:            An object holding all the available parameters for uploading.\n     - parameter progress:          The closure that is called periodically during the data transfer.\n     - parameter completionHandler: The closure to be called once the request is prepared, holding either the request object or an error\n     */\n    @discardableResult\n    open func signedUploadLarge(url: URL, params: CLDUploadRequestParams = CLDUploadRequestParams(), chunkSize: Int = defaultChunkSize, progress: ((Progress) -> Void)? = nil,\n                                completionHandler: CLDUploadCompletionHandler? = nil) -> CLDUploadRequest{\n        params.setSigned(true)\n        return performUploadLarge(url: url, params: params, preprocessChain: CLDPreprocessChain<Any>(), chunkSize: chunkSize, progress: progress, completionHandler: completionHandler)\n    }\n\n    /**\n    Uploads a file in chunks from the specified local-file URL to the configured cloud\n\n    - parameter url:               The URL pointing to the local file to upload.\n    - parameter params:            An object holding all the available parameters for uploading.\n    - parameter preprocessChain    A CLDPreprocessing chain containing processing steps and/or custom encoder to run on the resource before uploading\n    - parameter progress:          The closure that is called periodically during the data transfer.\n    - parameter completionHandler: The closure to be called once the request is prepared, holding either the request object or an error\n    */\n    @discardableResult\n    open func signedUploadLarge<T>(url: URL, params: CLDUploadRequestParams = CLDUploadRequestParams(), preprocessChain: CLDPreprocessChain<T>, chunkSize: Int = defaultChunkSize, progress: ((Progress) -> Void)? = nil,\n                                completionHandler: CLDUploadCompletionHandler? = nil) -> CLDUploadRequest{\n        params.setSigned(true)\n        return performUploadLarge(url: url, params: params, preprocessChain: preprocessChain, chunkSize: chunkSize, progress: progress, completionHandler: completionHandler)\n    }\n\n    fileprivate func performUploadLarge<T>(url: URL, params: CLDUploadRequestParams, preprocessChain: CLDPreprocessChain<T>, chunkSize: Int, progress: ((Progress) -> Void)? = nil,\n                                        completionHandler: CLDUploadCompletionHandler? = nil) -> CLDUploadRequest {\n\n        if (url.absoluteString.cldIsRemoteUrl()){\n            // send the request to the regular upload function (that handles remote urls)\n            return performUpload(data: url, params: params, preprocessChain: preprocessChain)\n        }\n        \n        let uploadRequest = CLDUploadRequestWrapper()\n        \n        if let handler = completionHandler {\n            uploadRequest.response(handler)\n        }\n        \n        if let progress = progress {\n            uploadRequest.progress(progress)\n        }\n        \n        guard chunkSize >= 5 * 1024 * 1024 else {\n            uploadRequest.setRequestError(CLDError.error(code: CLDError.CloudinaryErrorCode.generalErrorCode, message: \"Chunk size must be greater than 5[MB]\"))\n            return uploadRequest\n        }\n        \n        DispatchQueue.global().async {\n            let newUrl:URL\n            \n            if (preprocessChain.isEmpty()){\n                newUrl = url\n            } else {\n                do {\n                    newUrl = try preprocessChain.execute(resourceData: url)\n                } catch let error as NSError {\n                    uploadRequest.setRequestError(error)\n                    return\n                } catch {\n                    uploadRequest.setRequestError(CLDError.generalError())\n                    return\n                }\n            }\n            \n            let totalLength = CLDFileUtils.getFileSize(url: newUrl)\n            \n            guard totalLength != nil else {\n                uploadRequest.setRequestError (CLDError.error(code: CLDError.CloudinaryErrorCode.failedRetrievingFileInfo, message: \"zero file length\"))\n                return\n            }\n            \n            let randomId = NSUUID().uuidString\n            if let (baseUrl, parts) = CLDFileUtils.splitFile(url: newUrl, chunkSize: chunkSize) {\n                uploadRequest.setRequestsData(count: parts.count, totalLength: totalLength)\n                uploadRequest.cleanupHandler { success in\n                    DispatchQueue.global().async {\n                        CLDFileUtils.removeFile(file: baseUrl!)\n                    }\n                }\n                \n                for part in parts {\n                    let range = \"bytes \\(part.offset)-\\(part.offset + Int64(part.length - 1))/\\(totalLength!)\"\n                    uploadRequest.addRequest(self.performUpload(data: part.url, params: params, extraHeaders: [\"X-Unique-Upload-Id\": randomId, \"Content-Range\": range], preprocessChain: CLDPreprocessChain<Any>()))\n                }\n            } else {\n                uploadRequest.setRequestError (CLDError.error(code: CLDError.CloudinaryErrorCode.failedRetrievingFileInfo, message: \"Could not process file.\"))\n            }\n        }\n\n        return uploadRequest\n    }\n\n    fileprivate func performUpload<T>(data: Any, params: CLDUploadRequestParams, extraHeaders: [String:String]? = [:], preprocessChain:CLDPreprocessChain<T>, progress: ((Progress) -> Void)? = nil, completionHandler:((_ response: CLDUploadResult?, _ error: NSError?) -> ())? = nil) -> CLDUploadRequest {\n        \n        let uploadRequest:CLDUploadRequest\n        \n        // if preprocess or validations are required, we'll need to offload the work to a background queue\n        if preprocessChain.isEmpty(){\n            let request = networkCoordinator.upload(data, params: params, extraHeaders: extraHeaders)\n            uploadRequest = CLDDefaultUploadRequest(networkDataRequest: request)\n        } else {\n            let newRequest = CLDUploadRequestWrapper()\n            uploadRequest = newRequest\n            DispatchQueue.global().async {\n                do {\n                    let newUrl = try preprocessChain.execute(resourceData: data)\n                    let length = CLDFileUtils.getFileSize(url: newUrl)\n                    newRequest.setRequestsData(count: 1, totalLength: length)\n                    // perform upload with the newly created file url, and empty preprocessing (it's done already)\n                    newRequest.addRequest(self.performUpload(data: newUrl, params: params, extraHeaders: extraHeaders, preprocessChain: CLDPreprocessChain<Any>()))\n                } catch let error as NSError {\n                    newRequest.setRequestError(error)\n                } catch {\n                    newRequest.setRequestError(CLDError.generalError())\n                }\n            }\n        }\n        \n        if let completionHandler = completionHandler {\n            uploadRequest.response(completionHandler)\n        }\n        \n        if let progress = progress {\n            uploadRequest.progress(progress)\n        }\n        \n        return uploadRequest\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Uploader/Preupload/CLDPreprocessChain.swift",
    "content": "//\n//\n//  CLDPreprocessChain.swift\n//\n//  Copyright (c) 2017 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\npublic typealias CLDPreprocessStep<T> = (T) throws -> T\npublic typealias CLDResourceEncoder<T> = (T) throws -> URL?\n\n/**\n The CLDPreprocessChain is a generic base class used to run preprocessing on resources before uploading.\n Supports processing, validations and encoders, all fully customizable. Note: This class should not be used\n directly, use a concrete subclass (e.g. CLDImagePreprocessingChain).\n*/\npublic class CLDPreprocessChain<T> {\n    internal var encoder: CLDResourceEncoder<T>?\n\n    var chain = [CLDPreprocessStep<T>]()\n\n    internal init() {\n    }\n\n    /**\n      Returns true if the chain is empty (= NOP chain).\n    */\n    public func isEmpty() -> Bool {\n        return encoder == nil && chain.isEmpty\n    }\n\n    /**\n     Add a step to the chain, for preprocess or validation\n     \n      - parameter preprocess:  A CLDPreprocessStep to be used to encode the resource after the processing\n    */\n    @discardableResult\n    public func addStep(_ preprocess: @escaping CLDPreprocessStep<T>) -> Self {\n        chain.append(preprocess)\n        return self\n    }\n\n    /**\n     Set a custom resource encoder to use when saving the resource after executing the chain\n     \n      - parameter encoder:  A CLDResourceEncoder to be used to encode the resource after the processing\n    */\n    @discardableResult\n    public func setEncoder(_ encoder: @escaping CLDResourceEncoder<T>) -> Self {\n        self.encoder = encoder\n        return self\n    }\n\n    internal func execute(resourceData: Any) throws -> URL {\n        try verifyEncoder()\n        let resource: T? = try decodeResource(resourceData)\n        if var resource = resource {\n            for preprocess in chain {\n                resource = try preprocess(resource)\n            }\n\n            if let url = try encoder!(resource) {\n                return url\n            } else {\n                throw CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"Error encoding resource\")\n            }\n        } else {\n            throw CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"Error decoding resource\")\n        }\n    }\n\n    internal func decodeResource(_ resourceData: Any) throws -> T? {\n        throw CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"No decoder implemented - Did you mean to use ImagePreprocessChain?\")\n    }\n\n    internal func verifyEncoder() throws {\n        if (encoder == nil) {\n            throw CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"No encoder set - Did you mean to use ImagePreprocessChain?\")\n        }\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Uploader/RequestParams/CLDUploadRequestParams.swift",
    "content": "//\n//  CLDUploadRequestParams.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n This class represents the different parameters that can be passed when performing an upload request.\n For more information see the [documentation](http://cloudinary.com/documentation/image_upload_api_reference#upload).\n*/\n@objcMembers open class CLDUploadRequestParams: CLDRequestParams {\n\n    /**\n     A boolean variable representing whether or not the request should be signed.\n    */\n    internal var signed: Bool = false\n    \n    // MARK: Init\n    \n    public override init() {        \n        super.init()\n    }\n    \n    /**\n     Initializes a CLDUploadRequestParams instance.\n     \n     - parameter params:    A dictionary of the request parameters.\n     \n     - returns:             A new instance of CLDUploadRequestParams.\n     */\n    public init(params: [String : AnyObject]) {\n        super.init()\n        self.params = params\n    }\n    \n    internal override func merge(_ other: CLDRequestParams?){\n        super.merge(other)\n       \n        if let uploadRequest = other as? CLDUploadRequestParams {\n            self.signed = uploadRequest.signed\n        }\n    }\n    \n    // MARK: - Get Values\n    \n    open var publicId: String? {\n        return getParam(.PublicId) as? String\n    }\n    \n    open var format: String? {\n        return getParam(.Format) as? String\n    }\n    \n    open var type: String? {\n        return getParam(.FileType) as? String\n    }\n    \n    open var notificationUrl: String? {\n        return getParam(.NotificationUrl) as? String\n    }\n    \n    open var eagerNotificationUrl: String? {\n        return getParam(.EagerNotificationUrl) as? String\n    }\n    \n    open var proxy: String? {\n        return getParam(.Proxy) as? String\n    }\n    \n    open var folder: String? {\n        return getParam(.Folder) as? String\n    }\n    \n    open var moderation: String? {\n        return getParam(.Moderation) as? String\n    }\n    \n    open var accessControl: String? {\n        return getParam(.AccessControl) as? String\n    }\n    \n    open var eval: String? {\n        return getParam(.Eval) as? String\n    }\n    \n    open var rawConvert: String? {\n        return getParam(.RawConvert) as? String\n    }\n    \n    open var detection: String? {\n        return getParam(.Detection) as? String\n    }\n    \n    open var categorization: String? {\n        return getParam(.Categorization) as? String\n    }\n    \n    open var similaritySearch: String? {\n        return getParam(.SimilaritySearch) as? String\n    }\n    \n    open var autoTagging: String? {\n        return getParam(.AutoTagging) as? String\n    }\n    \n    open var backup: Bool? {\n        return getParam(.Backup) as? Bool\n    }\n    \n    open var useFilename: Bool? {\n        return getParam(.UseFilename) as? Bool\n    }\n    \n    open var uniqueFilename: Bool? {\n        return getParam(.UniqueFilename) as? Bool\n    }\n    \n    open var discardOriginalFilename: Bool? {\n        return getParam(.DiscardOriginalFilename) as? Bool\n    }\n\n    open var async: Bool? {\n        return getParam(.Async) as? Bool\n    }\n\n    open var eagerAsync: Bool? {\n        return getParam(.EagerAsync) as? Bool\n    }\n    \n    open var invalidate: Bool? {\n        return getParam(.Invalidate) as? Bool\n    }\n    \n    open var overwrite: Bool? {\n        return getParam(.Overwrite) as? Bool\n    }\n    \n    open var imageMetadata: Bool? {\n        return getParam(.ImageMetadata) as? Bool\n    }\n    \n    open var colors: Bool? {\n        return getParam(.Colors) as? Bool\n    }\n    \n    open var phash: Bool? {\n        return getParam(.Phash) as? Bool\n    }\n    \n    open var faces: Bool? {\n        return getParam(.Faces) as? Bool\n    }\n    \n    open var returnDeleteToken: Bool? {\n        return getParam(.ReturnDeleteToken) as? Bool\n    }\n    \n    open var transformation: String? {\n        return getParam(.Transformation) as? String\n    }\n    \n    open var tags: String? {\n        return getParam(.Tags) as? String\n    }\n    \n    open var allowedFormats: String? {\n        return getParam(.AllowedFormats) as? String\n    }\n    \n    open var context: String? {\n        return getParam(.Context) as? String\n    }\n    \n    open var faceCoordinates: String? {\n        return getParam(.FaceCoordinates) as? String\n    }\n    \n    open var customCoordinates: String? {\n        return getParam(.CustomCoordinates) as? String\n    }\n    \n    open var eager: String? {\n        return getParam(.Eager) as? String\n    }\n    \n    open var headers: String? {\n        return getParam(.Headers) as? String\n    }\n    \n    open var qualityAnalysis: Bool? {\n        return getParam(.QualityAnalysis) as? Bool\n    }\n    \n    open var accessibilityAnalysis: Bool? {\n        return getParam(.AccessibilityAnalysis) as? Bool\n    }\n    \n    open var ocr: Bool {\n        return getParam(.Ocr) as? String != nil\n    }\n    \n    open var backgroundRemoval: String? {\n        return getParam(.BackgroundRemoval) as? String\n    }\n    \n    open var filenameOverride: String? {\n        return getParam(.FilenameOverride) as? String\n    }\n\n    open var assetFolder: String? {\n        return getParam(.AssetFolder) as? String\n    }\n\n    open var publicIdPrefix: String? {\n        return getParam(.PublicIdPrefix) as? String\n    }\n\n    open var useFilenameAsDisplayName: Bool? {\n        return getParam(.UseFilenameAsDisplayName) as? Bool\n    }\n\n    open var displayName: String? {\n        return getParam(.DisplayName) as? String\n    }\n\n    open var autoChaptering: Bool? {\n        return getParam(.AutoChaptering) as? Bool\n    }\n\n    open var autoTranscription: Bool? {\n        return getParam(.AutoTranscription) as? Bool\n    }\n\n    fileprivate func getParam(_ param: UploadRequestParams) -> AnyObject? {\n        return params[param.rawValue] as AnyObject\n    }\n    \n    // MARK: Set Simple Params\n    \n    /**\n     Set the identifier that is used for accessing the uploaded resource. \n     A randomly generated ID is assigned if not specified. The Public ID may contain a full path including folders separated by a slash (/).\n     \n     - parameter publicId:          The identifier to set.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setPublicId(_ publicId: String) -> Self {\n        setParam(UploadRequestParams.PublicId.rawValue, value: publicId)\n        return self\n    }\n\n    /**\n     Set the identifier prefix that is used for accessing the uploaded resource.\n\n     - parameter prefix:    The prefix to prepend.\n\n     - returns:             The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setPublicIdPrefix(_ prefix: String) -> Self {\n        setParam(UploadRequestParams.PublicIdPrefix.rawValue, value: prefix)\n        return self\n    }\n    \n    /**\n     Set an optional format to convert the uploaded resource to before saving in the cloud. For example: jpg.\n     \n     - parameter format:            The format to convert to.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    open func setFormat(_ format: String) -> Self {\n        setParam(UploadRequestParams.Format.rawValue, value: format)\n        return self\n    }\n    \n    /**\n     Allows uploading resources as 'private' or 'authenticated' instead of the default public mode.\n     \n     - parameter type:              The type to set.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @objc(setTypeFromType:)\n    open func setType(_ type: CLDType) -> Self {        \n        return setType(String(describing: type))\n    }\n    \n    /**\n     Allows uploading resources as 'private' or 'authenticated' instead of the default public mode.\n     \n     - parameter type:              The type to set.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setType(_ type: String) -> Self {\n        setParam(UploadRequestParams.FileType.rawValue, value: type)\n        return self\n    }\n    \n    /**\n     Set an HTTP URL to send notification to (a webhook) when the upload is completed.\n     \n     - parameter notificationUrl:   The URL to set.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    open func setNotificationUrl(_ notificationUrl: String) -> Self {\n        setParam(UploadRequestParams.NotificationUrl.rawValue, value: notificationUrl)\n        return self\n    }\n    \n    /**\n     The default background removal behavior detects the foreground objects(s) of the image and removes the background.\n     You activate this behavior by setting the 'backgroundRemoval' parameter to 'cloudinary_ai' when uploading an image (Upload method)\n     or by using the Update method of the Admin API for existing images.\n     \n     - parameter backgroundRemoval: Use 'cloudinary_ai' or 'cloudinary_ai:[object_to_keep]'\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setBackgroundRemoval(_ backgroundRemoval: String) -> Self {\n        setParam(UploadRequestParams.BackgroundRemoval.rawValue, value: backgroundRemoval)\n        return self\n    }\n    \n    /**\n     Setting this params will override the original asset name.\n     \n     - parameter filenameOverride: New file name\n     \n     - returns:                    The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setFilenameOverride(_ filenameOverride: String) -> Self {\n        setParam(UploadRequestParams.FilenameOverride.rawValue, value: filenameOverride)\n        return self\n    }\n\n    /**\n     Setting this will generate chapters file.\n\n     - parameter autoChaptering: The boolean paramter\n\n     - returns:                    The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setAutoChpatering(_ autoChaptering: Bool) -> Self {\n        setParam(UploadRequestParams.AutoChaptering.rawValue, value: autoChaptering)\n        return self\n    }\n\n    /**\n     Setting this will generate transcription file.\n\n     - parameter autoChaptering: The boolean paramter\n\n     - returns:                    The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setAutoTranscription(_ autoTranscription: Bool) -> Self {\n        setParam(UploadRequestParams.AutoTranscription.rawValue, value: autoTranscription)\n        return self\n    }\n\n    /**\n     Set an HTTP URL to send notification to (a webhook) when the generation of eager transformations is completed.\n     \n     - parameter eagerNotificationUrl:      The URL to set.\n     \n     - returns:                             The same instance of CLDUploadRequestParams.\n     */\n    open func setEagerNotificationUrl(_ eagerNotificationUrl: String) -> Self {\n        setParam(UploadRequestParams.EagerNotificationUrl.rawValue, value: eagerNotificationUrl)\n        return self\n    }\n    \n    /**\n     Tells Cloudinary to upload resources from remote URLs through the given proxy. Format: http://hostname:port.\n     \n     - parameter proxy:     The proxy URL.\n     \n     - returns:             The same instance of CLDUploadRequestParams.\n     */\n    open func setProxy(_ proxy: String) -> Self {\n        setParam(UploadRequestParams.Proxy.rawValue, value: proxy)\n        return self\n    }\n    \n    /**\n     Set an optional folder name where the uploaded resource will be stored. The Public ID contains the full path of the uploaded resource, including the folder name.\n     \n     - parameter folder:    The folder URL.\n     \n     - returns:             The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setFolder(_ folder: String) -> Self {\n        setParam(UploadRequestParams.Folder.rawValue, value: folder)\n        return self\n    }\n\n    /**\n     Set an optional asset folder url where the uploaded resource will be stored.\n\n     - parameter assetFolder:    The folder URL.\n\n     - returns:                  The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setAssetFolder(_ assetFolder: String) -> Self {\n        setParam(UploadRequestParams.AssetFolder.rawValue, value: assetFolder)\n        return self\n    }\n\n    /**\n     Set the display name of the uploaded resource.\n\n     - parameter displayName:    The name of the resource.\n\n     - returns:                  The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setDisplayName(_ displayName: String) -> Self {\n        setParam(UploadRequestParams.DisplayName.rawValue, value: displayName)\n        return self\n    }\n\n    /**\n     Set A boolean parameter that determines whether to use the filename as the display name of the uploaded resource.\n\n     - parameter useFilenameAsDisplayName:    The boolean parameter.\n\n     - returns:                               The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setUseFilenameAsDisplayName(_ useFilenameAsDisplayName: Bool) -> Self {\n        setParam(UploadRequestParams.UseFilenameAsDisplayName.rawValue, value: useFilenameAsDisplayName)\n        return self\n    }\n    \n    /**\n     Set to manual to add the uploaded image to a queue of pending moderation images that can be moderated using the Admin API or the Cloudinary Management Console. \n     Set to webpurify to automatically moderate the uploaded image using the WebPurify Image Moderation add-on.\n     \n     - parameter moderation:        The moderation to set.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @objc(setModerationFromModeration:)\n    @discardableResult\n    open func setModeration(_ moderation: CLDModeration) -> Self {\n        return setModeration(String(describing: moderation))\n    }\n    \n    /**\n     Set to manual to add the uploaded image to a queue of pending moderation images that can be moderated using the [Cloudinary Management Console](https://cloudinary.com/console/media_library).\n     Set to webpurify to automatically moderate the uploaded image using the [WebPurify Image Moderation add-on](http://dev.cloudinary.com:3002/documentation/webpurify_image_moderation_addon).\n     \n     - parameter moderation:        The moderation to set.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    open func setModeration(_ moderation: String) -> Self {\n        setParam(UploadRequestParams.Moderation.rawValue, value: moderation)\n        return self\n    }\n    \n    /**\n     Set to aspose to automatically convert Office documents to PDF files and other image formats using the [Aspose Document Conversion add-on](http://dev.cloudinary.com:3002/documentation/aspose_document_conversion_addon).\n     \n     - parameter rawConvert:        The rawConvert to set.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setRawConvert(_ rawConvert: String) -> Self {\n        setParam(UploadRequestParams.RawConvert.rawValue, value: rawConvert)\n        return self\n    }\n    \n    /**\n     Set to adv_face to extract an extensive list of face attributes from a image using the [Advanced Facial Attribute Detection add-on](http://cloudinary.com/documentation/advanced_facial_attributes_detection_addon).\n     \n     - parameter detection:     The detection to set.\n     \n     - returns:                 The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setDetection(_ detection: String) -> Self {\n        setParam(UploadRequestParams.Detection.rawValue, value: detection)\n        return self\n    }\n    \n    /**\n     By setting the categorization parameter to imagga_tagging, Imagga is used to automatically classify the scenes of the uploaded image.\n     \n     - parameter categorization:    The categorization to set.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setCategorization(_ categorization: String) -> Self {\n        setParam(UploadRequestParams.Categorization.rawValue, value: categorization)\n        return self\n    }\n    \n    /**\n     \n     - parameter similaritySearch:      The similarity search to set.\n     \n     - returns:                         The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setSimilaritySearch(_ similaritySearch: String) -> Self {\n        setParam(UploadRequestParams.SimilaritySearch.rawValue, value: similaritySearch)\n        return self\n    }\n    \n    /**\n     - parameter accessControl:     A list of access control rules for the upload request\n     \n     - returns:                     The same instance CLDUploadRequestParams\n     */\n    @discardableResult\n    open func setAccessControl(_ accessControl: [CLDAccessControlRule]) -> Self {\n        setParam(UploadRequestParams.AccessControl.rawValue, value:  asJsonArray(arr: accessControl))\n        return self\n    }\n    \n    /**\n     - parameter accessControl:     A json string representing a list of access control rules for upload\n     \n     - returns:                     The same instance CLDUploadRequestParams\n     */\n    @objc(setAccessControlWithString:)\n    @discardableResult\n    open func setAccessControl(_ accessControl: String) -> Self {\n        setParam(UploadRequestParams.AccessControl.rawValue, value: accessControl)\n        return self\n    }\n    \n    /**\n     Set whether to assign tags to an image according to detected scene categories with a confidence score higher than the given value (between 0.0 and 1.0).\n     See [Imagga Auto Tagging](http://dev.cloudinary.com:3002/documentation/imagga_auto_tagging_addon) for more details.\n     \n     - parameter autoTagging:       The auto tagging parameter to use.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @objc(setAutoTaggingWithDouble:)\n    @discardableResult\n    open func setAutoTagging(_ autoTagging: Double) -> Self {\n        setAutoTagging(autoTagging.cldFormat(f: \".1\"))\n        return self\n    }\n    \n    /**\n     Set whether to assign tags to an image according to detected scene categories with a confidence score higher than the given value (between 0.0 and 1.0).\n     See [Imagga Auto Tagging](http://dev.cloudinary.com:3002/documentation/imagga_auto_tagging_addon) for more details.\n     \n     - parameter autoTagging:       The auto tagging parameter to use.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setAutoTagging(_ autoTagging: String) -> Self {\n        setParam(UploadRequestParams.AutoTagging.rawValue, value: autoTagging)\n        return self\n    }\n    \n    \n    // MARK: Set Boolean Params\n    \n    /**\n     Set A boolean parameter that determines whether to backup the uploaded resource. Overrides the default backup settings of your account.\n     \n     - parameter backup:        The boolean parameter.\n     \n     - returns:                 The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setBackup(_ backup: Bool) -> Self {\n        setBoolParam(.Backup, value: backup)\n        return self\n    }\n    \n    /**\n     Set A boolean parameter that determines whether to use the original file name of the uploaded resource if available for the Public ID. \n     The file name is normalized and random characters are appended to ensure uniqueness. Default: false.\n     \n     - parameter useFilename:   The boolean parameter.\n     \n     - returns:                 The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setUseFilename(_ useFilename: Bool) -> Self {\n        setBoolParam(.UseFilename, value: useFilename)\n        return self\n    }\n    \n    /**\n     When set to false, should not add random characters at the end of the filename that guarantee its uniqueness. Only relevant if use_filename is also set to true. Default: true.\n     \n     - parameter uniqueFilename:    The boolean parameter.\n     \n     - returns:                     The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setUniqueFilename(_ uniqueFilename: Bool) -> Self {\n        setBoolParam(.UniqueFilename, value: uniqueFilename)\n        return self\n    }\n    \n    /**\n     Set A boolean parameter that determines whether to discard the name of the original uploaded file. \n     Relevant when delivering resources as attachments (setting the flag transformation parameter to attachment). \n     Default: false.\n     \n     - parameter discardOriginalFilename:   The boolean parameter.\n     \n     - returns:                             The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setDiscardOriginalFilename(_ discardOriginalFilename: Bool) -> Self {\n        setBoolParam(.DiscardOriginalFilename, value: discardOriginalFilename)\n        return self\n    }\n\n    /**\n    Set a boolean parameter indicating whether to perform the image generation asynchronously. default is false.\n\n    - parameter async:      The boolean parameter.\n\n    - returns:              The same instance of CLDUploadRequestParams.\n    */\n    @discardableResult\n    open func setAsync(_ async: Bool) -> Self {\n        setBoolParam(UploadRequestParams.Async, value: async)\n        return self\n    }\n\n    /**\n     Set A boolean parameter that determines whether to generate the eager transformations asynchronously in the background. default is false.\n     \n     - parameter eagerAsync:    The boolean parameter.\n     \n     - returns:                 The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setEagerAsync(_ eagerAsync: Bool) -> Self {\n        setBoolParam(.EagerAsync, value: eagerAsync)\n        return self\n    }\n    \n    /**\n     Set boolean parameter indicating whether or not the asset should be invalidated through the CDN. default is false.\n     \n     - parameter invalidate:    The boolean parameter.\n     \n     - returns:             The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setInvalidate(_ invalidate: Bool) -> Self {\n        setBoolParam(.Invalidate, value: invalidate)\n        return self\n    }\n    \n    /**\n     Set boolean parameter indicating whether to overwrite existing resources with the same Public ID. When set to false, return immediately if a resource with the same Public ID was found. \n     Default: true (when using unsigned upload, the default is false and cannot be changed to true).\n     \n     - parameter overwrite:     The boolean parameter.\n     \n     - returns:                 The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setOverwrite(_ overwrite: Bool) -> Self {\n        setBoolParam(.Overwrite, value: overwrite)\n        return self\n    }\n    \n    /**\n     Set a boolean parameter indicating whether to retrieve IPTC and detailed Exif metadata of the uploaded asset. default is false.\n     \n     - parameter imageMetadata:     The boolean parameter.\n     \n     - returns:                     The same instance of CLDExplicitRequestParams.\n     */\n    @available(*, deprecated, message: \"Use the new method 'setMediaMetadata' instead.\")\n    @discardableResult\n    open func setImageMetadata(_ imageMetadata: Bool) -> Self {\n        setBoolParam(.ImageMetadata, value: imageMetadata)\n        return self\n    }\n\n    /**\n     Set a boolean parameter indicating whether to return IPTC, XMP, and detailed Exif metadata of the uploaded asset in the response. default is false.\n\n     - parameter mediaMetadata:     The boolean parameter.\n\n     - returns:                     The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setMediaMetadata(_ mediaMetadata: Bool) -> Self {\n        setBoolParam(.MediaMetadata, value: mediaMetadata)\n        return self\n    }\n\n    /**\n     Set a boolean parameter indicating whether to retrieve predominant colors & color histogram of the uploaded asset. default is false.\n     \n     - parameter colors:            The boolean parameter.\n     \n     - returns:                     The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setColors(_ colors: Bool) -> Self {\n        setBoolParam(.Colors, value: colors)\n        return self\n    }\n    \n    /**\n     Set a boolean parameter indicating whether to return the perceptual hash (pHash) on the uploaded asset.\n     The pHash acts as a fingerprint that allows checking image similarity. default is false.\n     \n     - parameter phash:             The boolean parameter.\n     \n     - returns:                     The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setPhash(_ phash: Bool) -> Self {\n        setBoolParam(.Phash, value: phash)\n        return self\n    }\n    \n    /**\n     Set a boolean parameter indicating whether to return the coordinates of faces contained in an uploaded asset (automatically detected or manually defined).\n     Each face is specified by the X & Y coordinates of the top left corner and the width & height of the face. default is false.\n     \n     - parameter faces:             The boolean parameter.\n     \n     - returns:                     The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setFaces(_ faces: Bool) -> Self {\n        setBoolParam(.Faces, value: faces)\n        return self\n    }\n    \n    /**\n     Set a boolean parameter indicating whether to return a deletion token in the upload response. \n     The token can be used to delete the uploaded resource within 10 minutes using an unauthenticated API request. \n     Default: false.\n     \n     - parameter returnDeleteToken:     The boolean parameter.\n     \n     - returns:                         The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setReturnDeleteToken(_ returnDeleteToken: Bool) -> Self {\n        setBoolParam(.ReturnDeleteToken, value: returnDeleteToken)\n        return self\n    }\n    \n    /**\n     Set a boolean parameter indicating whether to return quality analysis of the image.\n     Default: false.\n     \n     - parameter qualityAnalysis:     The boolean parameter.\n     \n     - returns:                       The same instance of CLDExplicitRequestParams.\n     */\n    @discardableResult\n    open func setQualityAnalysis(_ qualityAnalysis: Bool) -> Self {\n        setBoolParam(.QualityAnalysis, value: qualityAnalysis)\n        return self\n    }\n    \n    /**\n     Set a boolean parameter indicating whether to return accessibility analysis of the image.\n     Default: false.\n     \n     - parameter accessibilityAnalysis: The boolean parameter.\n     \n     - returns:                         The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setAccessibilityAnalysis(_ accessibilityAnalysis: Bool) -> Self {\n        setBoolParam(.AccessibilityAnalysis, value: accessibilityAnalysis)\n        return self\n    }\n    \n    /**\n    A setter for any one of the simple boolean parameters. This is used to normalize boolean values in requests\n    to be consistent across different platforms.\n    \n    - parameter value:              The parameter value.\n    - parameter param:              The boolean parameter to set.\n    \n    - returns:                       The same instance of CLDUploadRequestParams.\n    */\n    @discardableResult\n    fileprivate func setBoolParam(_ param: UploadRequestParams, value: Bool) -> Self {\n        let boolNumber = NSNumber(value: value as Bool)\n        setParam(param.rawValue, value: boolNumber)\n        return self\n    }\n    \n    // MARK: Set Params\n    \n    /**\n    Set the upload preset.\n    For more information see the [documentation](http://cloudinary.com/documentation/upload_images#unsigned_upload).\n    \n    - parameter uploadPreset:       The upload preset from your account settings.\n    \n    - returns:                       The same instance of CLDUploadRequestParams.\n    */\n    @discardableResult\n    open func setUploadPreset(_ uploadPreset: String) -> Self {\n        setParam(UploadRequestParams.UploadPreset.rawValue, value: uploadPreset)\n        return self\n    }\n    \n    /**\n    Set the request to be an unsigned request, using an upload preset that can be set in the Cloudinary account dashboard.\n    For more information see the [documentation](http://cloudinary.com/documentation/upload_images#unsigned_upload).\n\n    - parameter uploadPreset:       The upload preset from your account settings.\n\n    - returns:                       The same instance of CLDUploadRequestParams.\n    */\n    @discardableResult\n    @objc(setSignedWithBool:)\n    internal func setSigned(_ signed: Bool) -> Self {\n        self.signed = signed\n        return self\n    }\n\n    /**\n     Apply an incoming transformation as part of the upload request. \n     Any image transformation parameter can be specified as an option in the upload call and these transformations are applied before saving the image in the cloud.\n     For more information see the [documentation](http://cloudinary.com/documentation/upload_images#incoming_transformations).\n     \n     - parameter transformation:     The transformation to apply on the uploaded asset.\n     \n     - returns:                       The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    @objc(setTransformationFromTransformation:)\n    open func setTransformation(_ transformation: CLDTransformation) -> Self {\n        if let stringRep = transformation.asString() {\n            setTransformation(stringRep)\n        }\n        return self\n    }\n    \n    /**\n     Apply an incoming transformation as part of the upload request.\n     Any image transformation parameter can be specified as an option in the upload call and these transformations are applied before saving the image in the cloud.\n     For more information see the [documentation](http://cloudinary.com/documentation/upload_images#incoming_transformations).\n     \n     - parameter transformation:     The transformation to apply on the uploaded asset.\n     \n     - returns:                       The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setTransformation(_ transformation: String) -> Self {\n        setParam(UploadRequestParams.Transformation.rawValue, value: transformation)\n        return self\n    }\n    \n    /**\n     Assign tags to the uploaded files.\n     For more information see the [documentation](http://cloudinary.com/documentation/upload_images#tagging_images).\n     \n     - parameter tags:              The tags to aggign to the uploaded asset.\n     \n     - returns:                      The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    @objc(setTagsWithArray:)\n    open func setTags(_ tags: [String]) -> Self {\n        return setTags(tags.joined(separator: \",\"))\n    }\n    \n    /**\n     Assign tags to the uploaded files.\n     For more information see the [documentation](http://cloudinary.com/documentation/upload_images#tagging_images).\n     \n     - parameter tags:              The tags to aggign to the uploaded asset.\n     \n     - returns:                      The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setTags(_ tags: String) -> Self {\n        setParam(UploadRequestParams.Tags.rawValue, value: tags)\n        return self\n    }\n    \n    /**\n     Set An array of file formats that are allowed for uploading.\n     The default is any supported image format for images, and any kind of raw file.\n     Files of other types will be rejected.\n     The formats can be any combination of image types, video formats or raw file extensions.\n     For example: `mp4,ogv,jpg,png,pdf`\n     \n     - parameter allowedFormats:    The array of allowed formats.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    @objc(setAllowedFormatsWithArray:)\n    open func setAllowedFormats(_ allowedFormats: [String]) -> Self {\n        return setAllowedFormats(allowedFormats.joined(separator: \",\"))\n    }\n    \n    /**\n     Set An array of file formats that are allowed for uploading.\n     The default is any supported image format for images, and any kind of raw file.\n     Files of other types will be rejected.\n     The formats can be any combination of image types, video formats or raw file extensions.\n     For example: `mp4,ogv,jpg,png,pdf`\n     \n     - parameter allowedFormats:    The array of allowed formats.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setAllowedFormats(_ allowedFormats: String) -> Self {\n        setParam(UploadRequestParams.AllowedFormats.rawValue, value: allowedFormats)\n        return self\n    }\n    \n    /**\n     Set a dictionary of the key-value pairs of general textual context metadata to attach to an uploaded resource.\n     The context values of uploaded files are available for fetching using the Admin API.\n     For example: `alt=My image❘caption=Profile image`.\n     \n     - parameter context:       The context dictionary.\n     \n     - returns:                 The same instance of CLDUploadRequestParams.\n     \n     */\n    @objc(setContextFromDictionary:)\n    @discardableResult\n    open func setContext(_ context: [String : String]) -> Self {\n        return setContext(buildContextString(context))\n    }\n    \n    /**\n     Set a dictionary of the key-value pairs of general textual context metadata to attach to an uploaded resource.\n     The context values of uploaded files are available for fetching using the Admin API.\n     For example: `alt=My image❘caption=Profile image`.\n     \n     - parameter context:       The context dictionary.\n     \n     - returns:                 The same instance of CLDUploadRequestParams.\n     \n     */\n    @discardableResult\n    open func setContext(_ context: String) -> Self {\n        setParam(UploadRequestParams.Context.rawValue, value: context)\n        return self\n    }\n    \n    /**\n     Sets the coordinates of faces contained in an uploaded image and overrides the automatically detected faces. \n     Each face is specified by the X & Y coordinates of the top left corner and the width & height of the face.\n     \n     - parameter faceCoordinates:   The array of `CLDCoodinate` objects, each object holds a CGRect for a single face coordinate.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     \n     */\n    @objc(setFaceCoordinatesFromCoordinates:)\n    @discardableResult\n    open func setFaceCoordinates(_ faceCoordinates: [CLDCoordinate]) -> Self {\n        return setFaceCoordinates(buildCoordinatesString(faceCoordinates))\n    }\n    \n    /**\n     Sets the coordinates of faces contained in an uploaded image and overrides the automatically detected faces.\n     Each face is specified by the X & Y coordinates of the top left corner and the width & height of the face.\n     \n     - parameter faceCoordinates:   The array of `CLDCoodinate` objects, each object holds a CGRect for a single face coordinate.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     \n     */\n    @discardableResult\n    open func setFaceCoordinates(_ faceCoordinates: String) -> Self {\n        setParam(UploadRequestParams.FaceCoordinates.rawValue, value: faceCoordinates)\n        return self\n    }\n    \n    /**\n     Sets the coordinates of a region contained in an uploaded image that is subsequently used for cropping uploaded images using the custom gravity mode. \n     The region is specified by the X & Y coordinates of the top left corner and the width & height of the region.\n     \n     - parameter customCoordinates: The array of `CLDCoodinate` objects, each object holds a CGRect for a single custom coordinate.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     \n     */\n    @objc(setCustomCoordinatesFromCoordinates:)\n    @discardableResult\n    open func setCustomCoordinates(_ customCoordinates: [CLDCoordinate]) -> Self {\n        return setCustomCoordinates(buildCoordinatesString(customCoordinates))\n    }\n    \n    /**\n     Sets the coordinates of a region contained in an uploaded image that is subsequently used for cropping uploaded images using the custom gravity mode.\n     The region is specified by the X & Y coordinates of the top left corner and the width & height of the region.\n     \n     - parameter customCoordinates: The array of `CLDCoodinate` objects, each object holds a CGRect for a single custom coordinate.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     \n     */\n    @discardableResult\n    open func setCustomCoordinates(_ customCoordinates: String) -> Self {\n        setParam(UploadRequestParams.CustomCoordinates.rawValue, value: customCoordinates)\n        return self\n    }\n    \n    /**\n     Set an array of transformations to create for the uploaded resource during the upload process, instead of lazily creating each of them when first accessed by your site's visitors.\n     \n     - parameter eager:             The array of transformations (CLDTransformation|CLDEagerTransformation)\n\n     - returns:                     The same instance of CLDUploadRequestParams.\n     \n     */\n    @objc(setEagerFromTransformationArray:)\n    @discardableResult\n    open func setEager(_ eager: [CLDTransformation]) -> Self {\n        return setEager(buildEagerString(eager))\n    }\n\n    /**\n     Set an array of transformations to create for the uploaded resource during the upload process, instead of lazily creating each of them when first accessed by your site's visitors.\n     \n     - parameter eager:             The array of transformations.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     \n     */\n    @discardableResult\n    open func setEager(_ eager: String) -> Self {\n        setParam(UploadRequestParams.Eager.rawValue, value: eager)\n        return self\n    }\n    \n    /**\n     Override quality settings for the resource\n     \n     - parameter quality:           The quality configuration instance, see CLDQuality.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     \n     */\n    @objc(setQualityOverrideFromQuality:)\n    @discardableResult\n    open func setQualityOverride(_ quality: CLDTransformation.CLDQuality) -> Self {\n        setParam(UploadRequestParams.QualityOverride.rawValue, value: quality.description)\n        return self\n    }\n    \n    /**\n     Override quality settings for the resource\n\n     - parameter quality:           The quality as a string.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     \n     */\n    @objc(setQualityOverrideFromString:)\n    @discardableResult\n    open func setQualityOverride(_ quality: String) -> Self {\n        setParam(UploadRequestParams.QualityOverride.rawValue, value: quality)\n        return self\n    }\n    \n    /**\n    Allows modification on upload parameters by specifying custom logic with JavaScript code that is evaluated when uploading a file.\n    For more information see the [documentation](https://cloudinary.com/documentation/analysis_on_upload#evaluating_and_modifying_upload_parameters).\n    \n    - parameter eval:               The java script code to assign to the uploaded asset.\n    \n    - returns:                      The same instance of CLDUploadRequestParams.\n    */\n    @objc(setEvalFromString:)\n    @discardableResult\n    open func setEval(_ eval: String) -> Self {\n        setParam(UploadRequestParams.Eval.rawValue, value: eval)\n        return self\n    }\n    \n    /**\n     Set an array of headers lines for returning as response HTTP headers when delivering the uploaded resource to your users.\n     Supported headers: `Link, X-Robots-Tag`. \n     For example: `X-Robots-Tag: noindex`.\n     \n     - parameter headers:           The array of headers.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     \n     */\n    @objc(setHeadersWithDictionary:)\n    @discardableResult\n    open func setHeaders(_ headers: [String : String]) -> Self {\n        return setHeaders(buildHeadersString(headers))\n    }\n    \n    /**\n     Set an array of headers lines for returning as response HTTP headers when delivering the uploaded resource to your users.\n     Supported headers: `Link, X-Robots-Tag`.\n     For example: `X-Robots-Tag: noindex`.\n     \n     - parameter headers:           The array of headers.\n     \n     - returns:                     The same instance of CLDUploadRequestParams.\n     \n     */\n    @discardableResult\n    open func setHeaders(_ headers: String) -> Self {\n        setParam(UploadRequestParams.Headers.rawValue, value: headers)\n        return self\n    }\n    \n    /**\n     Requests that Cloudinary automatically find the best breakpoints, using an array of CLDResponsiveBreakpoints objects.\n     \n     - parameter responsiveBreakpoints:         The array of responsive breakpoints setting.\n     \n     - returns:                                 The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setResponsiveBreakpoints(_ responsiveBreakpoints: [CLDResponsiveBreakpoints]) -> Self {\n        var responsiveBreakpointsJSON: [String] = []\n\n        for rb in responsiveBreakpoints {\n            responsiveBreakpointsJSON.append(rb.description)\n        }\n\n        super.setParam(UploadRequestParams.ResponsiveBreakpoints.rawValue, value: \"[\\(responsiveBreakpointsJSON.joined(separator: \",\"))]\")\n\n        return self\n    }\n    \n    /**\n     Set a boolean parameter that determines whether to retrieve detected text information in the uploaded image file. default is false.\n     \n     - parameter enable:        The boolean parameter.\n     \n     - returns:                 The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    open func setOcr(_ enable: Bool) -> Self {\n        if enable {\n            setOcr(\"adv_ocr\")\n        } else {\n            setOcr(nil)\n        }\n        return self\n    }\n    /**\n     Set a boolean parameter that determines whether to retrieve detected text information in the uploaded image file. default is false.\n     \n     - parameter enable:        The boolean parameter.\n     \n     - returns:                 The same instance of CLDUploadRequestParams.\n     */\n    @discardableResult\n    @objc(setOcrString:)\n    open func setOcr(_ ocrString: String?) -> Self {\n        \n        if let string = ocrString , !string.isEmpty {\n            setParam(UploadRequestParams.Ocr.rawValue, value: string)\n        } else {\n            params.removeValue(forKey: UploadRequestParams.Ocr.rawValue)\n        }\n        return self\n    }\n    \n    // MARK: - Helpers\n    \n    fileprivate enum UploadRequestParams: String {\n        case PublicId =                             \"public_id\"\n        case PublicIdPrefix =                       \"public_id_prefix\"\n        case Callback =                             \"callback\"\n        case Format =                               \"format\"\n        case FileType =                             \"type\"\n        case NotificationUrl =                      \"notification_url\"\n        case EagerNotificationUrl =                 \"eager_notification_url\"\n        case Proxy =                                \"proxy\"\n        case Folder =                               \"folder\"\n        case AssetFolder =                          \"asset_folder\"\n        case Moderation =                           \"moderation\"\n        case RawConvert =                           \"raw_convert\"\n        case Categorization =                       \"categorization\"\n        case Detection =                            \"detection\"\n        case SimilaritySearch =                     \"similarity_search\"\n        case AutoTagging =                          \"auto_tagging\"\n        case UploadPreset =                         \"upload_preset\"\n        case AccessControl =                        \"access_control\"\n        case QualityOverride =                      \"quality_override\"\n        case Eval =                                 \"eval\"\n        case DisplayName =                          \"display_name\"\n\n        // Boolean params\n        case UseFilenameAsDisplayName =             \"use_filename_as_display_name\"\n        case Backup =                               \"backup\"\n        case Exif =                                 \"exif\"\n        case Faces =                                \"faces\"\n        case Colors =                               \"colors\"\n        case ImageMetadata =                        \"image_metadata\"\n        case MediaMetadata =                        \"media_metadata\"\n        case UseFilename =                          \"use_filename\"\n        case UniqueFilename =                       \"unique_filename\"\n        case DiscardOriginalFilename =              \"discard_original_filename\"\n        case Async =                                \"async\"\n        case EagerAsync =                           \"eager_async\"\n        case Invalidate =                           \"invalidate\"\n        case Overwrite =                            \"overwrite\"\n        case Phash =                                \"phash\"\n        case ReturnDeleteToken =                    \"return_delete_token\"\n        case QualityAnalysis =                      \"quality_analysis\"\n        case AccessibilityAnalysis =                \"accessibility_analysis\"\n        \n        case Transformation =                       \"transformation\"\n        case Tags =                                 \"tags\"\n        case AllowedFormats =                       \"allowed_formats\"\n        case Context =                              \"context\"\n        case FaceCoordinates =                      \"face_coordinates\"\n        case CustomCoordinates =                    \"custom_coordinates\"\n        case Eager =                                \"eager\"\n        case Headers =                              \"headers\"\n        case ResponsiveBreakpoints =                \"responsive_breakpoints\"\n        case Ocr =                                  \"ocr\"\n        case BackgroundRemoval =                    \"background_removal\"\n        case FilenameOverride =                     \"filename_override\"\n        case AutoChaptering =                       \"auto_chaptering\"\n        case AutoTranscription =                    \"auto_transcription\"\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Uploader/Requests/CLDDefaultUploadRequest.swift",
    "content": "//\n//  CLDDefaultUploadRequest.swift\n//\n//  Copyright (c) 2017 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n A `CLDUploadRequest` object is returned when creating a data transfer request to Cloudinary, e.g. uploading a file.\n It allows the options to add a progress closure that is called periodically during the transfer\n and a response closure to be called once the transfer has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\ninternal class CLDDefaultUploadRequest: CLDUploadRequest {\n\n\n    internal var networkRequest: CLDNetworkDataRequest\n\n    internal init(networkDataRequest: CLDNetworkDataRequest) {\n        networkRequest = networkDataRequest\n    }\n\n\n    // MARK: - Public\n\n    /**\n     Resume the request.\n     */\n    open override func resume() {\n        networkRequest.resume()\n    }\n\n    /**\n     Suspend the request.\n     */\n    open override func suspend() {\n        networkRequest.suspend()\n    }\n\n    /**\n     Cancel the request.\n     */\n    open override func cancel() {\n        networkRequest.cancel()\n    }\n\n    //MARK: Handlers\n\n    /**\n     Set a response closure to be called once the request has finished.\n\n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n\n     - returns:                          The same instance of CLDUploadRequest.\n     */\n\n    @discardableResult\n    open override func responseRaw(_ completionHandler: @escaping (_ response: Any?, _ error: NSError?) -> ()) -> CLDUploadRequest {\n        networkRequest.response(completionHandler)\n        return self\n    }\n\n    /**\n     Set a response closure to be called once the request has finished.\n\n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n\n     - returns:                          The same instance of CLDUploadRequest.\n     */\n    @discardableResult\n    open override func response(_ completionHandler: @escaping (_ result: CLDUploadResult?, _ error: NSError?) -> ()) -> CLDUploadRequest {\n        responseRaw { (response, error) in\n            if let res = response as? [String : AnyObject] {\n                completionHandler(CLDUploadResult(json: res), nil)\n            } else {\n                completionHandler(nil, error ?? CLDError.generalError())\n            }\n        }\n        return self\n    }\n\n    /**\n     Set a progress closure that is called periodically during the data transfer.\n\n     - parameter progressBlock:          The closure that is called periodically during the data transfer.\n\n     - returns:                          The same instance of CLDUploadRequest.\n     */\n    @discardableResult\n    open override func progress(_ progress: @escaping ((Progress) -> Void)) -> CLDUploadRequest {\n        networkRequest.progress(progress)\n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Uploader/Requests/CLDUploadRequest.swift",
    "content": "//\n//  CLDUploadRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n A `CLDUploadRequest` object is returned when creating a data transfer request to Cloudinary, e.g. uploading a file.\n It allows the options to add a progress closure that is called periodically during the transfer\n and a response closure to be called once the transfer has finished,\n as well as performing actions on the request, such as cancelling, suspending or resuming it.\n */\n@objcMembers open class CLDUploadRequest : NSObject {\n    internal override init() {\n    }\n    \n    /**\n     Resume the request.\n     */\n    open func resume(){}\n    \n    /**\n     Suspend the request.\n     */\n    open func suspend(){}\n    \n    /**\n     Cancel the request.\n     */\n    open func cancel(){}\n    \n    //MARK: Handlers\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDUploadRequest.\n     */\n    \n    @discardableResult\n    open func responseRaw(_ completionHandler: @escaping (_ response: Any?, _ error: NSError?) -> ()) -> CLDUploadRequest{\n        return self\n    }\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDUploadRequest.\n     */\n    @discardableResult\n    open func response(_ completionHandler: @escaping (_ result: CLDUploadResult?, _ error: NSError?) -> ()) -> CLDUploadRequest{\n        return self\n    }\n    \n    /**\n     Set a progress closure that is called periodically during the data transfer.\n     \n     - parameter progress:               The closure that is called periodically during the data transfer.\n     \n     - returns:                          The same instance of CLDUploadRequest.\n     */\n    @discardableResult\n    open func progress(_ progress: @escaping ((Progress) -> Void)) -> CLDUploadRequest{\n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Uploader/Requests/CLDUploadRequestWrapper.swift",
    "content": "//\n//  CLDUploadRequestWrapper.swift\n//\n//  Copyright (c) 2017 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n/**\n A `CLDUploadRequestWrapper` object is a wrapper for instances of `CLDUploadRequest`. This is returned as a promise from\n several `CLDUploader` functions, in case the actual concrete request cannot yet be created. This is also allows for multiple\n concrete requests to be represented as one request. This class is used for preprocessing requests as well as uploda large requests.\n */\ninternal class CLDUploadRequestWrapper: CLDUploadRequest {\n    private var state = RequestState.started\n    fileprivate var requestsCount: Int!\n    fileprivate var totalLength: Int64!\n    fileprivate var requestsProgress = [CLDUploadRequest: Int64]()\n    fileprivate var totalProgress: Progress?\n    fileprivate var progressHandler: ((Progress) -> Void)?\n    fileprivate var requests = [CLDUploadRequest]()\n    fileprivate var result: CLDUploadResult?\n    fileprivate var error: NSError?\n    fileprivate let queue = DispatchQueue(label: \"RequestsHandlingQueue\", attributes: .concurrent)\n    fileprivate let closureQueue: OperationQueue = {\n        let operationQueue = OperationQueue()\n        operationQueue.name = \"com.cloudinary.CLDUploadRequestWrapper\"\n        operationQueue.maxConcurrentOperationCount = 1\n        operationQueue.isSuspended = true\n        return operationQueue\n    }()\n    \n    /**\n     Once the count and total length of the request are known this method should be called.\n     Without this information the progress closures will not be called.\n     \n     - parameter count:         Number of inner requests expected to be added (or already added).\n     - parameter totalLength:   Total length, in bytes, of the uploaded resource (can be spread across several inner request for `uploadLarge`)\n     */\n    internal func setRequestsData(count: Int, totalLength: Int64?) {\n        self.totalLength = totalLength ?? 0\n        self.requestsCount = count\n        self.totalLength = totalLength ?? 0\n        self.totalProgress = Progress(totalUnitCount: self.totalLength)\n    }\n\n    /**\n     Add a requst to be part of the wrapping request.\n     \n     - parameter request:   An upload request to add - This is usually a concrete `CLDDefaultUploadRequest` to be part of this wrapper.\n     */\n    internal func addRequest(_ request: CLDUploadRequest) {\n        queue.sync() {\n            guard self.state != RequestState.cancelled && self.state != RequestState.error else {\n                return\n            }\n\n            if (self.state == RequestState.suspended) {\n                request.suspend()\n            }\n\n            request.response() { result, error in\n                guard (self.state != RequestState.cancelled && self.state != RequestState.error) else {\n                    return\n                }\n\n                if (error != nil) {\n                    // single part error fails everything\n                    self.state = RequestState.error\n                    self.cancel()\n                    self.requestDone(nil, error)\n                } else if self.requestsCount == 1 || (result?.done ?? false) {\n                    // last part arrived successfully\n                    self.state = RequestState.success\n                    self.requestDone(result, nil)\n                }\n            }\n\n            request.progress() { innerProgress in\n                guard (self.state != RequestState.cancelled && self.state != RequestState.error) else {\n                    return\n                }\n\n                self.requestsProgress[request] = innerProgress.completedUnitCount\n                \n                if let totalProgress = self.totalProgress {\n                    totalProgress.completedUnitCount = self.requestsProgress.values.reduce(0, +)\n                    self.progressHandler?(totalProgress)\n                }\n            }\n\n            self.requests.append(request)\n        }\n    }\n\n    /**\n     This is used in case the request fails even without any inner upload request (e.g. when the preprocessing fails).\n     Once the error is set here it will be send once the completion closures are set.\n     \n     - parameter error: The NSError to set.\n     */\n    internal func setRequestError(_ error: NSError) {\n        state = RequestState.error\n        requestDone(nil, error)\n    }\n\n    fileprivate func requestDone(_ result: CLDUploadResult?, _ error: NSError?) {\n        self.error = error\n        self.result = result\n        requestsProgress.removeAll()\n        requests.removeAll()\n        closureQueue.isSuspended = false\n    }\n\n    // MARK: - Public\n\n    /**\n     Resume the request.\n     */\n    open override func resume() {\n        queue.sync() {\n            state = RequestState.started\n            for request in requests {\n                request.resume()\n            }\n        }\n    }\n\n    /**\n     Suspend the request.\n     */\n    open override func suspend() {\n        queue.sync() {\n            state = RequestState.suspended\n            for request in requests {\n                request.suspend()\n            }\n        }\n    }\n\n    /**\n     Cancel the request.\n     */\n    open override func cancel() {\n        queue.sync() {\n            state = RequestState.cancelled\n            for request in requests {\n                request.cancel()\n            }\n        }\n    }\n\n    //MARK: Handlers\n\n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CldUploadRequestWrapper.\n     */\n    @discardableResult\n    open override func response(_ completionHandler: @escaping (_ result: CLDUploadResult?, _ error: NSError?) -> ()) -> Self {\n        closureQueue.addOperation {\n            completionHandler(self.result, self.error)\n        }\n\n        return self\n    }\n\n    /**\n     Set a progress closure that is called periodically during the data transfer.\n     \n     - parameter progressBlock:          The closure that is called periodically during the data transfer.\n     \n     - returns:                          The same instance of CLDUploadRequestWrapper.\n     */\n    @discardableResult\n    open override func progress(_ progress: @escaping ((Progress) -> Void)) -> Self {\n        self.progressHandler = progress\n        return self\n    }\n\n    /**\n    Sets a cleanup handler that is called when the request doesn't need it's resources anymore.\n     This is called whether the request succeeded or not.\n     \n     - Parameter handler:   The closure to be called once cleanup is necessary.\n     \n     - returns:             The same instance of CLDUploadRequestWrapper.\n     */\n    @discardableResult\n    internal func cleanupHandler(handler: @escaping (_ success: Bool) -> ()) -> Self {\n        closureQueue.addOperation {\n            handler(self.state == RequestState.success)\n        }\n        return self\n    }\n}\n\nfileprivate enum RequestState: Int {\n    case started, suspended, cancelled, error, success\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Uploader/Results/CLDUploadResult.swift",
    "content": "//\n//  CLDUploadResult.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n@objcMembers open class CLDUploadResult: CLDBaseResult {\n    \n    \n    // MARK: - Getters\n\n    open var type: String? {\n        return getParam(.urlType) as? String\n    }\n\n    open var eager: [CLDEagerResult]? {\n        guard let eagerArr = getParam(.eager) as? [[String : AnyObject]] else {\n            return nil\n        }\n        var eager: [CLDEagerResult] = []\n        for singleEager in eagerArr {\n            eager.append(CLDEagerResult(json: singleEager))\n        }\n        return eager\n    }\n\n    open var publicId: String? {\n        return getParam(.publicId) as? String\n    }\n    \n    open var version: String? {\n        guard let version = getParam(.version) else {\n            return nil\n        }\n        return String(describing: version)\n    }\n    \n    open var url: String? {\n        return getParam(.url) as? String\n    }\n    \n    open var secureUrl: String? {\n        return getParam(.secureUrl) as? String\n    }\n    \n    open var resourceType: String? {\n        return getParam(.resourceType) as? String\n    }\n    \n    open var signature: String? {\n        return getParam(.signature) as? String\n    }\n    \n    open var createdAt: String? {\n        return getParam(.createdAt) as? String\n    }\n    \n    open var length: Double? {\n        return getParam(.length) as? Double\n    }\n    \n    open var tags: [String]? {\n        return getParam(.tags) as? [String]\n    }\n    \n    open var moderation: AnyObject? {\n        return getParam(.moderation)\n    }\n\n    open var accessControl: ([CLDAccessControlRule])? {\n        if let rules = getParam(.accessControl) as? [[String: String]] {\n            let result:[CLDAccessControlRule] = rules.compactMap{fromJson(object: $0)}\n            if !result.isEmpty {\n                return result\n            }\n        }\n\n        return nil\n    }\n\n    open var context: [String:[String:String]]? {\n        var result: [String:[String:String]]? = nil\n        if let c = getParam(.context) as? [String:AnyObject] {\n            result = [:]\n            for k in c.keys {\n                result![k] = c[k] as? [String:String]\n            }\n        }\n        return result;\n    }\n\n    open var responsiveBreakpoints: [ResponsiveBreakpointsResult]? {\n        var result = [ResponsiveBreakpointsResult]()\n        if let jsonNodes = getParam(UploadResultKey.responsiveBreakpoints) as? [[String: AnyObject]] {\n            for json in jsonNodes {\n                result.append(ResponsiveBreakpointsResult(json: json))\n            }\n        }\n\n        return result\n    }\n\n    // MARK: Image Params\n    \n    open var width: Int? {\n        return getParam(.width) as? Int\n    }\n    \n    open var height: Int? {\n        return getParam(.height) as? Int\n    }\n    \n    open var format: String? {\n        return getParam(.format) as? String\n    }\n    \n    open var exif: [String : String]? {\n        return getParam(.exif) as? [String : String]\n    }\n    \n    open var metadata: [String : String]? {\n        return getParam(.metadata) as? [String : String]\n    }\n    \n    open var faces: AnyObject? {\n        return getParam(.faces)\n    }\n    \n    open var colors: AnyObject? {\n        return getParam(.colors)\n    }\n    \n    open var phash: String? {\n        return getParam(.phash) as? String\n    }\n    \n    open var deleteToken: String? {\n        return getParam(.deleteToken) as? String\n    }\n    \n    open var originalFilename: String? {\n        return getParam(.originalFilename) as? String\n    }\n\n    open var playbackUrl: String? {\n        return getParam(.playbackUrl) as? String\n    }\n\n    open var info: CLDInfo? {\n        guard let info = getParam(.info) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDInfo(json: info)\n    }\n    \n    @available(*, deprecated, message: \"Use qualityAnalysisResult instead.\")\n    open var qualityAnalysis: [String : AnyObject]? {\n        return getParam(.qualityAnalysis) as? [String : AnyObject]\n    }\n    \n    open var qualityAnalysisResult: CLDQualityAnalysis? {\n        guard let qualityAnalysis = getParam(.qualityAnalysis) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDQualityAnalysis(json: qualityAnalysis)\n    }\n    \n    // MARK: Video Params\n    \n    open var video: CLDVideo? {\n        guard let video = getParam(.video) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDVideo(json: video)\n    }\n    \n    open var audio: CLDAudio? {\n        guard let audio = getParam(.audio) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDAudio(json: audio)\n    }\n    \n    open var frameRte: Double? {\n        return getParam(.frameRate) as? Double\n    }\n    \n    open var bitRate: Int? {\n        return getParam(.bitRate) as? Int\n    }\n    \n    open var duration: Double? {\n        return getParam(.duration) as? Double\n    }\n    \n    open var done: Bool? {\n        return getParam(.done) as? Bool\n    }\n\n    open var assetFolder: String? {\n        return getParam(.assetFolder) as? String\n    }\n\n    open var displayName: String? {\n        return getParam(.displayName) as? String\n    }\n    \n    open var accessibilityAnalysis: CLDAccessibilityAnalysisResult? {\n        guard let accessibilityAnalysis = getParam(.accessibilityAnalysis) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDAccessibilityAnalysisResult(json: accessibilityAnalysis)\n    }\n    \n    open var coordinates: CLDCoordinates? {\n        guard let coordinates = getParam(CommonResultKeys.coordinates) as? [String : AnyObject] else {\n            return nil\n        }\n        return CLDCoordinates(json: coordinates)\n    }\n\n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: UploadResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    enum UploadResultKey: CustomStringConvertible {\n        case signature, done, deleteToken, responsiveBreakpoints\n        case video, audio, frameRate, bitRate, duration // Video\n        \n        var description: String {\n            switch self {\n            case .signature:                return \"signature\"\n            case .done:                     return \"done\"\n            case .deleteToken:              return \"delete_token\"\n            case .responsiveBreakpoints:    return \"responsive_breakpoints\"\n            case .video:                    return \"video\"\n            case .audio:                    return \"audio\"\n            case .frameRate:                return \"frame_rate\"\n            case .bitRate:                  return \"bit_rate\"\n            case .duration:                 return \"duration\"\n            }\n        }\n    }\n}\n\n\n// MARK: - Video Result\n\n@objcMembers open class CLDVideo: CLDBaseResult {\n    \n    open var format: String? {\n        return getParam(.pixFormat) as? String\n    }\n    \n    open var codec: String? {\n        return getParam(.codec) as? String\n    }\n    \n    open var level: Int? {\n        return getParam(.level) as? Int\n    }\n    \n    open var bitRate: Int? {\n        return getParam(.bitRate) as? Int\n    }\n\n    open var metadata: [String: String]? {\n        return getParam(.videoMetadata) as? [String: String]\n    }\n\n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: VideoKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum VideoKey: CustomStringConvertible {\n        case pixFormat, codec, level, bitRate, videoMetadata\n\n        var description: String {\n            switch self {\n            case .pixFormat:        return \"pix_format\"\n            case .codec:            return \"codec\"\n            case .level:            return \"level\"\n            case .bitRate:          return \"bit_rate\"\n            case .videoMetadata:         return \"metadata\"\n            }\n        }\n    }\n}\n\n\n@objcMembers open class CLDEagerResult: CLDBaseResult {\n\n    // MARK: - Getters\n\n    open var url: String? {\n        return getParam(.url) as? String\n    }\n\n    open var secureUrl: String? {\n        return getParam(.secureUrl) as? String\n    }\n}\n\n@objcMembers open class CLDAudio: CLDBaseResult {\n    \n    open var codec: String? {\n        return getParam(.codec) as? String\n    }\n    \n    open var bitRate: Int? {\n        return getParam(.bitRate) as? Int\n    }\n    \n    open var frequency: Int? {\n        return getParam(.frequency) as? Int\n    }\n    \n    open var channels: Int? {\n        return getParam(.channels) as? Int\n    }\n    \n    open var channelLayout: String? {\n        return getParam(.channelLayout) as? String\n    }\n\n    // MARK: - Private Helpers\n    \n    fileprivate func getParam(_ param: AudioKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n    \n    fileprivate enum AudioKey: CustomStringConvertible {\n        case codec, bitRate, frequency, channels, channelLayout\n\n        var description: String {\n            switch self {\n            case .codec:            return \"codec\"\n            case .bitRate:          return \"bit_rate\"\n            case .frequency:        return \"frequency\"\n            case .channels:         return \"channels\"\n            case .channelLayout:    return \"channel_layout\"\n            }\n        }\n    }\n}\n\n@objc open class ResponsiveBreakpointsResult : CLDBaseResult {\n\n    // MARK: - Getters\n\n    open var breakpoints: [ResponsiveBreakpoint]? {\n        var result = [ResponsiveBreakpoint]()\n        if let jsonNodes = getParams(ResponsiveBreakpointResultKey.breakpoints) as? [[String: AnyObject]] {\n            for json in jsonNodes {\n                result.append(ResponsiveBreakpoint(json: json))\n            }\n        }\n\n        return result\n    }\n\n    open var transformation: String? {\n        return getParams(ResponsiveBreakpointResultKey.transformation) as? String\n    }\n\n    // MARK: - Private Helpers\n\n    fileprivate func getParams(_ param: ResponsiveBreakpointResultKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n\n    fileprivate enum ResponsiveBreakpointResultKey : CustomStringConvertible {\n        case breakpoints, transformation\n\n        var description: String {\n            switch self {\n            case .breakpoints:      return \"breakpoints\"\n            case .transformation:   return \"transformation\"\n            }\n        }\n    }\n}\n\n@objc open class ResponsiveBreakpoint : CLDBaseResult {\n\n    open var width : Int? {\n        return getParam(ResponsiveBreakpointKey.width) as? Int\n    }\n\n    open var height : Int? {\n        return getParam(ResponsiveBreakpointKey.height) as? Int\n    }\n\n    open var bytes : Int? {\n        return getParam(ResponsiveBreakpointKey.bytes) as? Int\n    }\n\n    open var url : String? {\n        return getParam(ResponsiveBreakpointKey.url) as? String\n    }\n\n    open var secureUrl : String? {\n        return getParam(ResponsiveBreakpointKey.secureUrl) as? String\n    }\n\n    fileprivate func getParam(_ param: ResponsiveBreakpointKey) -> AnyObject? {\n        return resultJson[String(describing: param)]\n    }\n\n    fileprivate enum ResponsiveBreakpointKey : CustomStringConvertible {\n        case bytes, width, secureUrl, url, height\n\n        var description: String {\n            switch self {\n            case .bytes:        return \"bytes\"\n            case .width:        return \"width\"\n            case .secureUrl:    return \"secure_url\"\n            case .url:          return \"url\"\n            case .height:       return \"height\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Features/Url/CLDUrl.swift",
    "content": "//\n//  CLDUrl.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n/**\n The CLDUrl class represents a URL to a remote asset either on your Cloudinary cloud, or from another remote source.\n*/\n@objcMembers open class CLDUrl: NSObject {\n    \n    fileprivate struct CLDUrlConsts {\n        static let CLD_OLD_AKAMAI_CHARED_CDN = \"cloudinary-a.akamaihd.net\"\n        static let CLD_SHARED_CDN = \"res\\(CLD_COM)\"\n        static let CLD_COM = \".cloudinary.com\"\n    }\n\n    /**\n     The Cloudinary public ID of the resource\n    */\n    fileprivate var publicId: String?\n    /**\n     The current Cloudinary session configuration.\n    */\n    fileprivate var config: CLDConfiguration!\n    \n    /**\n     The media source of the URL. default is upload.\n     */\n    fileprivate var type: String = String(describing: CLDType.upload)\n    \n    /**\n     The resource type of the remote asset that the URL points to. default is image.\n     */\n    fileprivate var resourceType: String = String(describing: CLDUrlResourceType.image)\n    \n    /**\n     The format of the remote asset that the URL points to.\n     */\n    fileprivate var format: String?\n    \n    /**\n     The version of the remote asset that the URL points to.\n     */\n    fileprivate var version: String?\n    \n    /**\n     A suffix to the URL that points to the remote asset (private CDN only, image/upload and raw/upload only).\n     */\n    fileprivate var suffix: String?\n    \n    /**\n     Indicates whether to use a root path instead of a full path (image/upload only).\n     */\n    fileprivate var useRootPath: Bool = false\n    \n    /**\n     Indicates whether to use a shorten URL (image/upload only).\n     */\n    fileprivate var shortenUrl: Bool = false\n    \n    /**\n     The transformation to be apllied on the remote asset.\n     */\n    fileprivate var transformation: CLDTransformation?\n    \n    /**\n     Indicates whether to add '/v1/' to the URL when the public ID includes folders and a 'version' value was\n     not defined.\n     When no version is explicitly specified and the public id contains folders, a default v1 version\n     is added to the url. This boolean can disable that behaviour.     */\n    fileprivate var forceVersion: Bool = true\n    \n    // MARK: - Init\n    \n    fileprivate override init() {\n        super.init()\n    }\n    \n    internal init(configuration: CLDConfiguration) {\n        config = configuration\n        super.init()\n    }\n\n    // MARK: - Set Values\n    \n    /**\n    Set the media source of the URL.\n    \n    - parameter publicId:    the media source to set.\n    \n    - returns:               the same instance of CLDUrl.\n    */\n    open func setPublicId(_ publicId: String) -> CLDUrl {\n        self.publicId = publicId\n        return self\n    }\n\n    /**\n    Set the media source of the URL.\n\n    - parameter type:       the media source to set.\n\n    - returns:               the same instance of CLDUrl.\n    */\n    @objc(setTypeFromType:)\n    open func setType(_ type: CLDType) -> CLDUrl {\n        return setType(String(describing: type))\n    }\n\n    /**\n     Set the media source of the URL.\n     \n     - parameter type:       the media source to set.\n     \n     - returns:               the same instance of CLDUrl.\n     */\n    open func setType(_ type: String) -> CLDUrl {\n        self.type = type\n        return self\n    }\n    \n    /**\n     Set the resource type of the asset the URL points to.\n     \n     - parameter resourceType:      the resource type to set.\n     \n     - returns:                      the same instance of CLDUrl.\n     */\n    @objc(setResourceTypeFromUrlResourceType:)\n    open func setResourceType(_ resourceType: CLDUrlResourceType) -> CLDUrl {\n        return setResourceType(String(describing: resourceType))\n    }\n    \n    /**\n     Set the resource type of the asset the URL points to.\n     \n     - parameter resourceType:      the resource type to set.\n     \n     - returns:                      the same instance of CLDUrl.\n     */\n    open func setResourceType(_ resourceType: String) -> CLDUrl {\n        self.resourceType = resourceType\n        return self\n    }\n    \n    /**\n     Set the format of the asset the URL points to.\n     \n     - parameter format:            the format to set.\n     \n     - returns:                      the same instance of CLDUrl.\n     */\n    open func setFormat(_ format: String) -> CLDUrl {\n        self.format = format\n        return self\n    }\n    \n    \n    /**\n     Set the version of the asset the URL points to.\n     \n     - parameter version:            the version to set.\n     \n     - returns:                      the same instance of CLDUrl.\n     */\n    open func setVersion(_ version: String) -> CLDUrl {\n        self.version = version\n        return self\n    }\n    \n    /**\n     Set the suffix of the URL. (private CDN only, image/upload and raw/upload only).\n     \n     - parameter suffix:            the suffix to set.\n     \n     - returns:                      the same instance of CLDUrl.\n     */\n    open func setSuffix(_ suffix: String) -> CLDUrl {\n        self.suffix = suffix\n        return self\n    }\n    \n    /**\n     Set whether to use a root path instead of a full path. (image/upload only).\n     \n     - parameter useRootPath:       Indicates whether to use a root path instead of a full path.\n     \n     - returns:                      the same instance of CLDUrl.\n     */\n    open func setUseRootPath(_ useRootPath: Bool) -> CLDUrl {\n        self.useRootPath = useRootPath\n        return self\n    }\n    \n    /**\n     Set whether to use a shorten URL. (image/upload only).\n     \n     - parameter shortenUrl:       Indicates whether to use a shorten URL.\n     \n     - returns:                      the same instance of CLDUrl.\n     */\n    open func setShortenUrl(_ shortenUrl: Bool) -> CLDUrl {\n        self.shortenUrl = shortenUrl\n        return self\n    }\n    \n    /**\n     Indicates whether to add '/v1/' to the URL when the public ID includes folders and a 'version' value was\n     not defined.\n     When no version is explicitly specified and the public id contains folders, a default v1 version\n     is added to the url. Set this boolean as false to prevent that behaviour.\n     \n     - parameter forceVersion:        Indicates whether to add the version.\n     \n     - returns:                         the same instance of CLDUrl.\n     */\n    open func setForceVersion(_ forceVersion: Bool) -> CLDUrl {\n        self.forceVersion = forceVersion\n        return self\n    }\n    \n    /**\n     Set the transformation to be apllied on the remote asset.\n     \n     - parameter transformation:    The transformation to be apllied on the remote asset.\n     \n     - returns:                      the same instance of CLDUrl.\n     */\n    @discardableResult\n    open func setTransformation(_ transformation: CLDTransformation) -> CLDUrl {\n        self.transformation = transformation\n        return self\n    }\n    \n    // MARK: - Actions\n\n    /**\n     Generate a string URL representation of the CLDUrl.\n\n     - parameter signUrl:       Indicates whether to generate a signature out of the API secret and add it to the generated URL. Default is false.\n\n     - returns:                  The generated string URL representation.\n     */\n    open func generate(signUrl: Bool = false) -> String? {\n        if let publicId = self.publicId {\n            return generate(publicId, signUrl: signUrl)\n        } else {\n            return nil\n        }\n    }\n\n    /**\n     Generate a string URL representation of the CLDUrl.\n     \n     - parameter publicId:      The remote asset's name (e.g. the public id of an uploaded image).\n     - parameter signUrl:       Indicates whether to generate a signature out of the API secret and add it to the generated URL. Default is false.\n     \n     - returns:                  The generated string URL representation.\n     */\n    open func generate(_ publicId: String, signUrl: Bool = false) -> String? {\n        \n        if signUrl && config.apiSecret == nil {\n            printLog(.error, text: \"Must supply api_secret for signing urls\")\n            return nil\n        }\n        \n        var sourceName = publicId\n        var resourceType = self.resourceType\n        var type = self.type\n        var version = self.version ?? String()\n        var format = self.format\n        \n        \n        let preloadedComponentsMatch = GenerateUrlRegex.preloadedRegex.matches(in: sourceName, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, sourceName.count))\n        if preloadedComponentsMatch.count > 0 {\n            if let preloadedComponents = preloadedComponentsMatch.first {\n                resourceType = (sourceName as NSString).substring(with: preloadedComponents.rangeAt(1))\n                type = (sourceName as NSString).substring(with: preloadedComponents.rangeAt(2))\n                version = (sourceName as NSString).substring(with: preloadedComponents.rangeAt(3))\n                sourceName = (sourceName as NSString).substring(with: preloadedComponents.rangeAt(4))\n            }\n        }\n        \n        let transformation = self.transformation ?? CLDTransformation()\n        if let unwrappedFormat = format , !unwrappedFormat.isEmpty && type == String(describing: CLDType.fetch) {\n            transformation.setFetchFormat(unwrappedFormat)\n            format = nil\n        }\n        \n        guard let transformationStr = transformation.asString() else {\n                printLog(.error, text: \"An invalid transformation was added.\")\n                return nil\n        }\n        \n        if  forceVersion &&\n            version.isEmpty &&\n            sourceName.contains(\"/\") &&\n            sourceName.range(of: \"^v[0-9]+/.*\", options: NSString.CompareOptions.regularExpression, range: nil, locale: nil) == nil &&\n            sourceName.range(of: \"^https?:/.*\", options: [NSString.CompareOptions.regularExpression, NSString.CompareOptions.caseInsensitive], range: nil, locale: nil) == nil\n        {\n            version = \"1\"\n        }\n        \n        if !version.isEmpty {\n            version = \"v\\(version)\"\n        }\n        \n        var toSign: String = String()\n        if !transformationStr.isEmpty {\n            toSign.append(\"\\(transformationStr)/\")\n        }\n        \n        if sourceName.range(of: \"^https?:/.*\", options: [NSString.CompareOptions.regularExpression, NSString.CompareOptions.caseInsensitive], range: nil, locale: nil) != nil {\n            if let encBasename = sourceName.cldSmartEncodeUrl() {\n                toSign.append(encBasename)\n                sourceName = encBasename\n            }\n        }\n        else {\n            if let encBasename = sourceName.removingPercentEncoding?.cldSmartEncodeUrl() {\n                toSign.append(encBasename)\n                sourceName = encBasename\n            }\n            \n            if let suffix = suffix , !suffix.isEmpty {\n                if suffix.range(of: \"[/\\\\.]\", options: NSString.CompareOptions.regularExpression, range: nil, locale: nil) != nil {\n                    printLog(.error, text: \"URL Suffix should not include . or /\")\n                    return nil\n                }\n                sourceName = \"\\(sourceName)/\\(suffix)\"\n            }\n            \n            if let unwrappedFormat = format {\n                sourceName = \"\\(sourceName).\\(unwrappedFormat)\"\n                toSign.append(\".\\(unwrappedFormat)\")\n            }\n        }\n        \n        let prefix = finalizePrefix(sourceName)\n        guard let resourceTypeAndType = finalizeResourceTypeAndType(resourceType, type: type)\n            else {\n                return nil\n        }\n        \n        var signature = String()\n        if signUrl {\n            if let apiSecret = config.apiSecret {\n                toSign.append(apiSecret)\n            }\n            \n            if config.longUrlSignature {\n                // long url forces sha256 algorithm\n                let encoded = toSign.sha256_base64()\n                signature = \"s--\\(encoded[0...31])--\"\n            }\n            else {\n                switch config.signatureAlgorithm {\n                case .sha1:\n                    let encoded = toSign.sha1_base64()\n                    signature = \"s--\\(encoded[0...7])--\"\n                case .sha256:\n                    let encoded = toSign.sha256_base64()\n                    signature = \"s--\\(encoded[0...7])--\"\n                }\n            }\n        }\n\n        \n        var url = [prefix, resourceTypeAndType, signature, transformationStr, version , sourceName].joined(separator: \"/\").replacingOccurrences(of: \" \", with: \"%20\")\n\n        //Analytics\n        if let urlObject = URL(string: url) {\n            if(config.analytics && urlObject.query == nil) {\n                let analytics = \"_a=\" + config.analyticsObject.generateAnalyticsSignature()\n                url = url + \"?\" + analytics\n            }\n        }\n        \n        let regex = try! NSRegularExpression(pattern: \"([^:])\\\\/+\", options: NSRegularExpression.Options.caseInsensitive)\n        \n        return regex.stringByReplacingMatches(in: url, options: [], range: NSMakeRange(0, url.count), withTemplate: \"$1/\")\n    }\n    \n    fileprivate struct GenerateUrlRegex {\n        fileprivate static let preloadedRegexString = \"^([^/]+)/([^/]+)/v([0-9]+)/([^#]+)(#[0-9a-f]+)?$\"\n        static let preloadedRegex: NSRegularExpression = {\n            return try! NSRegularExpression(pattern:preloadedRegexString, options: NSRegularExpression.Options.caseInsensitive)\n        }()\n    }\n    \n    // MARK: - Helpers\n    \n    fileprivate func finalizePrefix(_ basename: String) -> String {\n        var prefix = String()\n\n        if config.secure {\n            var secureDistribution = String()\n            if let secureDist = config.secureDistribution , (secureDist != CLDUrlConsts.CLD_OLD_AKAMAI_CHARED_CDN && !secureDist.isEmpty) {\n                secureDistribution = secureDist\n            }\n            else {\n                secureDistribution = config.privateCdn ? \"\\(config.cloudName!)-\\(CLDUrlConsts.CLD_SHARED_CDN)\" : CLDUrlConsts.CLD_SHARED_CDN\n            }\n            \n            if config.secureCdnSubdomain {\n                let sharedDomain = \"res-\\(basename.toCRC32() % 5 + 1)\\(CLDUrlConsts.CLD_COM)\"\n                secureDistribution = secureDistribution.replacingOccurrences(of: CLDUrlConsts.CLD_SHARED_CDN, with: sharedDomain)\n            }\n            \n            prefix = \"https://\\(secureDistribution)\"\n        }\n        else if let cname = config.cname {\n            prefix = \"http://\"\n            if config.cdnSubdomain {\n                prefix += \"a\\(basename.toCRC32() % 5 + 1).\"\n            }\n            \n            prefix += cname\n        }\n        else {\n            prefix = \"http://\"\n            if config.privateCdn {\n                prefix += \"\\(config.cloudName!)-\"\n            }\n            prefix += \"res\"\n            if config.cdnSubdomain {\n                prefix += \"-\\(basename.toCRC32() % 5 + 1)\"\n            }\n            prefix += CLDUrlConsts.CLD_COM\n        }\n        \n        if !config.privateCdn {\n            prefix += \"/\\(config.cloudName!)\"\n        }\n        return prefix\n    }\n    \n    fileprivate func finalizeResourceTypeAndType(_ resourceType: String, type: String) -> String? {\n        if !config.privateCdn, let urlSuffix = suffix , !urlSuffix.isEmpty {\n            printLog(.error, text: \"URL Suffix only supported in private CDN\")\n            return nil\n        }\n        \n        var resourceTypeAndType = \"\\(resourceType)/\\(type)\"\n        if let urlSuffix = suffix , !urlSuffix.isEmpty {\n            if resourceTypeAndType == \"\\(String(describing: CLDUrlResourceType.image))/\\(String(describing: CLDType.upload))\" {\n               resourceTypeAndType = \"images\"\n            }\n            else if resourceTypeAndType == \"\\(String(describing: CLDUrlResourceType.image))/\\(String(describing: CLDType.private))\" {\n                resourceTypeAndType = \"private_images\"\n            }\n            else if resourceTypeAndType == \"\\(String(describing: CLDUrlResourceType.raw))/\\(String(describing: CLDType.upload))\" {\n                resourceTypeAndType = \"files\"\n            }\n            else {\n                printLog(.error, text: \"URL Suffix only supported for image/upload, image/private and raw/upload\")\n                return nil\n            }\n        }\n        \n        if useRootPath {\n            if resourceTypeAndType == \"\\(String(describing: CLDUrlResourceType.image))/\\(String(describing: CLDType.upload))\" || resourceTypeAndType == \"images\" {\n               resourceTypeAndType = String()\n            }\n            else {\n                printLog(.error, text: \"Root path only supported for image/upload\")\n                return nil\n            }\n        }\n        \n        if shortenUrl && resourceTypeAndType == \"\\(String(describing: CLDUrlResourceType.image))/\\(String(describing: CLDType.upload))\" {\n            resourceTypeAndType = \"iu\"\n        }\n        \n        return resourceTypeAndType\n    }\n    \n   \n}\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Network/Adapter/CLDNetworkAdapter.swift",
    "content": "//\n//  NetworkAdapter.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n\n// MARK: CLDNetworkAdapter\n\n/**\nA protocol defining the way the SDK works with its network layer, allowing the implementation of a custom network layer.\nBy default the Cloudinary SDK uses CLDNetworkDelegate() as its network adapter,\nto use a custom network adapter you must implement the `CLDNetworkAdapter` protocol and send it when creating the CLDCloudinary instance.\n*/\n@objc public protocol CLDNetworkAdapter {\n    \n    // MARK: Actions\n    \n    /**\n    Create a network request for the given URL, with the specified headers and body parameters.\n    \n    - parameter url:            The URL to make the request to.\n    - parameter headers:        A dictionary of the headers to set to the request.\n    - parameter parameters:     A dictionary of the parameters to set to the request.\n    \n    - returns:                  An instance implementing the protocol `CLDNetworkDataRequest`,\n                                allowing the options to add response closure to be called once the request has finished,\n                                as well as performing actions on the request, such as cancelling, suspending or resuming it.\n    */\n    func cloudinaryRequest(_ url: String, headers: [String : String], parameters: [String : Any]) -> CLDNetworkDataRequest\n    \n    /**\n     Create a network upload request for the given URL, with the specified headers, body parameters and data.\n     \n     - parameter url:            The URL to make the request to.\n     - parameter headers:        A dictionary of the headers to set to the request.\n     - parameter parameters:     A dictionary of the parameters to set to the request.\n     - parameter data:           Can receive either the data to upload or an NSURL to either a local or a remote file to upload.\n\n     - returns:                 An instance implementing the protocol `CLDNetworkDataRequest`,\n                                allowing the options to add a progress closure that is called periodically during the upload\n                                and a response closure to be called once the upload is finished,\n                                as well as performing actions on the request, such as cancelling, suspending or resuming it.\n     */\n    func uploadToCloudinary(_ url: String, headers: [String : String], parameters: [String : Any],  data: Any) -> CLDNetworkDataRequest\n    \n    /**\n     Download a file from the specified url.\n     \n     - parameter url:           The URL of the file to download.\n     \n     - returns:                 An instance implementing the protocol `CLDNetworkDataRequest`,\n                                allowing the option to set a closure returning the fetched image when its available.\n                                The protocol also allows the options to add a progress closure that is called periodically during the download,\n                                as well as cancelling the request.\n     */\n    func downloadFromCloudinary(_ url: String) -> CLDNetworkDataRequest\n    \n    // MARK: Setters\n    \n    /**\n    Set a completion handler provided by the UIApplicationDelegate `application:handleEventsForBackgroundURLSession:completionHandler:` method.\n    The handler will be called automaticaly once the session finishes its events for background URL session.\n    \n    default is `nil`.\n    */\n    func setBackgroundCompletionHandler(_ newValue: (() -> ())?)\n    \n    /**\n     The maximum number of queued downloads that can execute at the same time.\n     \n     The default value of this property is NSOperationQueueDefaultMaxConcurrentOperationCount.\n     */\n    func setMaxConcurrentDownloads(_ maxConcurrentDownloads: Int)\n    \n    // MARK: Getters\n    /**\n    Get the completion handler to be called automaticaly once the session finishes its events for background URL session.\n    \n    default is `nil`.\n    */\n    func getBackgroundCompletionHandler() -> (() -> ())?\n}\n\n\n// MARK: - CLDNetworkRequest\n\n/**\nThe `CLDNetworkRequest` protocol is returned when creating a network request using one of Cloudinary's API calls.\nIt allows the options to add a response closure to be called once the request has finished,\nas well as performing actions on the request, such as cancelling, suspending or resuming it.\n*/\n@objc public protocol CLDNetworkRequest {\n    \n    // MARK: Actions\n    \n    /**\n    Resume the request.\n    */\n    func resume()\n    \n    /**\n     Suspend the request.\n     */\n    func suspend()\n    \n    /**\n     Cancel the request.\n     */\n    func cancel()\n    \n}\n\n// MARK: - CLDNetworkDataRequest\n\n/**\nThe `CLDNetworkDataRequest` protocol is returned when creating a data transfer request to Cloudinary, e.g. uploading a file.\nIt allows the options to add a progress closure that is called periodically during the transfer\nand a response closure to be called once the transfer has finished,\nas well as performing actions on the request, such as cancelling, suspending or resuming it.\n*/\n@objc public protocol CLDNetworkDataRequest: CLDNetworkRequest {\n    \n    //MARK: Handlers\n\n    /**\n    Set a progress closure that is called periodically during the data transfer.\n    \n    - parameter progress:          The closure that is called periodically during the data transfer.\n    \n    - returns:                     The same instance of CLDNetworkDataRequest.\n    */\n    @discardableResult\n    func progress(_ progress: ((Progress) -> Void)?) -> CLDNetworkDataRequest\n    \n    /**\n     Set a response closure to be called once the request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the response object or the error.\n     \n     - returns:                          The same instance of CLDNetworkRequest.\n     */\n    @discardableResult\n    func response(_ completionHandler: ((_ response: Any?, _ error: NSError?) -> ())?) -> CLDNetworkRequest\n}\n\n\n// MARK: - CLDFetchImageRequest\n\n/**\nThe `CLDFetchImageRequest` protocol is returned when creating a fetch image request.\nIt allows the option to set a closure returning the fetched image when its available.\nThe protocol also allows the options to add a progress closure that is called periodically during the download,\nas well as cancelling the request.\n*/\n@objc public protocol CLDFetchImageRequest: CLDNetworkDataRequest {\n    \n    //MARK: Actions\n      \n    /**\n     Set a response closure to be called once the fetch image request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the retrieved UIImage or the error.\n     \n     - returns:                          The same instance of CLDFetchImageRequest.\n     */\n    @discardableResult\n    func responseImage(_ completionHandler: CLDCompletionHandler?) -> CLDFetchImageRequest\n}\n\n/**\nThe `CLDFetchAssetRequest` protocol is returned when creating a fetch asset request.\nIt allows the option to set a closure returning the fetched asset when its available.\nThe protocol also allows the options to add a progress closure that is called periodically during the download,\nas well as cancelling the request.\n*/\n@objc public protocol CLDFetchAssetRequest: CLDNetworkDataRequest {\n    \n    //MARK: Actions\n      \n    /**\n     Set a response closure to be called once the fetch asset request has finished.\n     \n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the retrieved Data or the error.\n     \n     - returns:                          The same instance of CLDFetchAssetRequest.\n     */\n    @discardableResult\n    func responseAsset(_ completionHandler: CLDAssetCompletionHandler?) -> CLDFetchAssetRequest\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Network/CLDDefaultNetworkAdapter.swift",
    "content": "//\n//  CLDDefaultNetworkAdapter.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal class CLDDefaultNetworkAdapter: NSObject, CLDNetworkAdapter {\n\n    init(configuration: URLSessionConfiguration? = nil) {\n        if let configuration = configuration {\n            manager = CLDNSessionManager(configuration: configuration)\n        } else {\n            let configuration: URLSessionConfiguration = {\n                let configuration = URLSessionConfiguration.background(withIdentifier: SessionProperties.networkIdentifier)\n                configuration.httpAdditionalHeaders = CLDNSessionManager.defaultHTTPHeaders\n                return configuration\n            }()\n            manager = CLDNSessionManager(configuration: configuration)\n        }\n        manager.startRequestsImmediately = false\n    }\n\n    fileprivate let manager: CLDNSessionManager\n\n    fileprivate let downloadQueue: OperationQueue = {\n        let operationQueue = OperationQueue()\n        operationQueue.name = \"com.cloudinary.CLDDefaultNetworkAdapter\"\n        return operationQueue\n    }()\n\n    internal static let sharedAdapter             = CLDDefaultNetworkAdapter()\n    \n    private struct SessionProperties {\n        static let networkIdentifier: String = Bundle.main.bundleIdentifier ?? \"\" + \".cloudinarySDKbackgroundSession\"\n        static let downloadIdentifier: String = \"\" + \".cloudinarySDKbackgroundDownloadSession\"\n    }\n\n    // MARK: Features\n    internal func cloudinaryRequest(_ url: String, headers: [String: String], parameters: [String: Any]) -> CLDNetworkDataRequest {\n        let req: CLDNDataRequest = manager.request(url, method: .post, parameters: parameters, headers: headers)\n        req.resume()\n        return CLDNetworkDataRequestImpl(request: req)\n    }\n\n    internal func uploadToCloudinary(_ url: String, headers: [String: String], parameters: [String: Any], data: Any) -> CLDNetworkDataRequest {\n        var parameters = parameters\n        let timeout = parameters.removeValue(forKey: \"timeout\") as? NSNumber\n        let asyncUploadRequest = CLDAsyncNetworkUploadRequest()\n        manager.upload(multipartFormData: { (multipartFormData) in\n\n            if let data = data as? Data {\n                multipartFormData.append(data, withName: \"file\", fileName: \"file\", mimeType: \"application/octet-stream\")\n            } else if let url = data as? URL {\n                if url.absoluteString.cldIsRemoteUrl() {\n                    if let urlAsData = url.absoluteString.data(using: String.Encoding.utf8) {\n                        multipartFormData.append(urlAsData, withName: \"file\")\n                    }\n                } else {\n                    multipartFormData.append(url, withName: \"file\", fileName: url.lastPathComponent, mimeType: \"application/octet-stream\")\n                }\n            }\n\n            for key in parameters.keys {\n                if let value = parameters[key], value is [String] {\n                    if let valueArr = value as? [String] {\n                        for paramValue in valueArr {\n                            if let valueData = paramValue.data(using: String.Encoding.utf8) {\n                                multipartFormData.append(valueData, withName: key + \"[]\")\n                            }\n                        }\n                    }\n                } else if let value = parameters[key] as? String {\n                    if value.isEmpty {\n                        continue\n                    }\n\n                    if let valueData = value.data(using: String.Encoding.utf8) {\n                        multipartFormData.append(valueData, withName: key)\n                    }\n                } else if let value = parameters[key] as? Bool {\n                    if let valueData = String(describing: NSNumber(value: value)).data(using: String.Encoding.utf8) {\n                        multipartFormData.append(valueData, withName: key)\n                    }\n                }\n            }\n\n        }, usingThreshold: UInt64(), to: url, method: .post, headers: headers, timeout: timeout) { (encodingResult) in\n            switch encodingResult {\n            case .success(let upload, _, _):\n                upload.resume()\n                let uploadRequest = CLDNetworkUploadRequest(request: upload)\n                asyncUploadRequest.networkDataRequest = uploadRequest\n            case .failure(let encodingError):\n                asyncUploadRequest.networkDataRequest = CLDRequestError(error: encodingError)\n            }\n        }\n\n        return asyncUploadRequest\n    }\n\n    internal func downloadFromCloudinary(_ url: String) -> CLDNetworkDataRequest {\n        let req = manager.request(url)\n        downloadQueue.addOperation { () -> () in\n            req.resume()\n        }\n        return CLDNetworkDownloadRequest(request: req)\n    }\n\n    // MARK: - Setters\n    internal func setBackgroundCompletionHandler(_ newValue: (() -> ())?) {\n        manager.backgroundCompletionHandler = newValue\n    }\n\n    internal func setMaxConcurrentDownloads(_ maxConcurrentDownloads: Int) {\n        downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads\n    }\n\n    // MARK: - Getters\n    internal func getBackgroundCompletionHandler() -> (() -> ())? {\n        return manager.backgroundCompletionHandler\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Network/CLDNetworkCoordinator.swift",
    "content": "//\n//  NetworkCoordinator.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport UIKit\n\ninternal class CLDNetworkCoordinator: NSObject {\n\n    static let DEFAULT_VERSION =        \"5.2.5\"\n    \n    fileprivate struct CLDNetworkCoordinatorConsts {\n        static let BASE_CLOUDINARY_URL =    \"https://api.cloudinary.com\"\n        static let API_KEY =                \"api_key\"\n    }\n    \n    fileprivate var config: CLDConfiguration\n    fileprivate var networkAdapter: CLDNetworkAdapter\n    fileprivate var extraHeaders: [String: String]?\n\n    // MARK: - Init\n    \n    init(configuration: CLDConfiguration, networkAdapter: CLDNetworkAdapter = CLDDefaultNetworkAdapter.sharedAdapter) {\n        config = configuration\n        self.networkAdapter = networkAdapter\n    }\n\n    init(configuration: CLDConfiguration, sessionConfiguration: URLSessionConfiguration) {\n        config = configuration\n        self.networkAdapter = CLDDefaultNetworkAdapter(configuration: sessionConfiguration)\n    }\n\n    // MARK: - Actions\n    \n    internal func callAction(_ action: CLDAPIAction, params: CLDRequestParams) -> CLDNetworkDataRequest {\n        \n        let url = getUrl(action, resourceType: params.resourceType)\n        let headers = getHeaders()\n        \n        params.setTimeout(from: config)\n        let requestParams = getSignedRequestParams(params)\n        \n        return networkAdapter.cloudinaryRequest(url, headers: headers, parameters: requestParams)\n    }\n    \n    internal func upload(_ data: Any, params: CLDUploadRequestParams, extraHeaders: [String:String]?=[:]) -> CLDNetworkDataRequest {\n        let url = getUrl(.Upload, resourceType: params.resourceType)\n        params.setTimeout(from: config)\n        let requestParams = params.signed ? getSignedRequestParams(params) : params.params\n        var headers :[String : String] = getHeaders()\n        headers.cldMerge(self.extraHeaders) //User's configured extra headers\n        headers.cldMerge(extraHeaders)\n        return networkAdapter.uploadToCloudinary(url, headers: headers, parameters: requestParams,  data: data)\n    }\n    \n    internal func download(_ url: String) -> CLDNetworkDataRequest {\n        return networkAdapter.downloadFromCloudinary(url)\n    }\n    \n    // MARK: - Helpers\n    \n    fileprivate func getSignedRequestParams(_ requestParams: CLDRequestParams) -> [String : Any] {\n        var params: [String : Any] = requestParams.params\n        \n        guard let apiKey = requestParams.apiKey ?? config.apiKey else {\n            printLog(.error, text: \"Must supply api key for a signed request\")\n            return params\n        }\n        \n        if let signatureObj = requestParams.signature {\n            params[CLDSignature.SignatureParam.Signature.rawValue] = signatureObj.signature\n            params[CLDSignature.SignatureParam.Timestamp.rawValue] = cldParamValueAsString(value: signatureObj.timestamp)\n        }\n        else if let apiSecret = config.apiSecret {\n            let timestamp = Int(Date().timeIntervalSince1970)\n            params[CLDSignature.SignatureParam.Timestamp.rawValue] = cldParamValueAsString(value: timestamp)\n            \n            let signature = cloudinarySignParamsUsingSecret(getSignParams(from: params), cloudinaryApiSecret: apiSecret, signatureVersion: config.signatureVesion)\n            params[CLDSignature.SignatureParam.Signature.rawValue] = signature\n        }\n        else {\n            printLog(.error, text: \"Must supply api secret for a signed request\")\n        }\n        \n        params[CLDNetworkCoordinatorConsts.API_KEY] = apiKey\n        return params\n    }\n    \n    fileprivate func getSignParams(from params: [String : Any]) -> [String : Any] {\n        var signatureParams = params\n        signatureParams.removeValue(forKey: CLDConfiguration.ConfigParam.Timeout.description)\n        return signatureParams\n    }\n    \n    fileprivate func getUrl(_ action: CLDAPIAction, resourceType: String?) -> String {\n        var urlComponents: [String] = []\n        let prefix = config.uploadPrefix ?? CLDNetworkCoordinatorConsts.BASE_CLOUDINARY_URL\n        urlComponents.append(prefix)\n        urlComponents.append(\"v1_1\")\n        urlComponents.append(config.cloudName)\n        if action != CLDAPIAction.DeleteByToken {\n            let rescourceType = resourceType ?? String(describing: CLDUrlResourceType.image)\n            urlComponents.append(rescourceType)\n        }\n        urlComponents.append(action.rawValue)\n        return urlComponents.joined(separator: \"/\")\n    }\n    \n    fileprivate func getHeaders() -> [String : String] {\n        var headers: [String : String] = [:]\n        var userAgent: String\n        if let userPlatform = config.userPlatform {\n            userAgent = \"\\(userPlatform.platform)/\\(userPlatform.version) CloudinaryiOS/\\(CLDNetworkCoordinator.getVersion())\"\n        }\n        else {\n            userAgent = \"CloudinaryiOS/\\(CLDNetworkCoordinator.getVersion())\"\n        }\n\n        userAgent += \" (\\(UIDevice.current.model); \\(UIDevice.current.systemName) \\(UIDevice.current.systemVersion))\"\n\n        headers[\"User-Agent\"] = userAgent\n        headers[\"X-Requested-With\"] = \"XMLHttpRequest\"\n\n        return headers\n    }\n    \n    static func getVersion() -> String {\n        let version = DEFAULT_VERSION\n        return version\n    }\n    \n    internal enum CLDAPIAction: String, CustomStringConvertible {\n        case Upload =                       \"upload\"\n        case Rename =                       \"rename\"\n        case Destroy =                      \"destroy\"\n        case Tags =                         \"tags\"\n        case Explicit =                     \"explicit\"\n        case Explode =                      \"explode\"\n        case GenerateArchive =              \"generate_archive\"\n        case GenerateSprite =               \"sprite\"\n        case Multi =                        \"multi\"\n        case GenerateText =                 \"text\"\n        case DeleteByToken =                \"delete_by_token\"\n        \n        var description: String {\n            switch self {\n            case .Upload:                   return \"upload\"\n            case .Rename:                   return \"rename\"\n            case .Destroy:                  return \"destroy\"\n            case .Tags:                     return \"tags\"\n            case .Explicit:                 return \"explicit\"\n            case .Explode:                  return \"explode\"\n            case .GenerateArchive:          return \"generate_archive\"\n            case .GenerateSprite:           return \"sprite\"\n            case .Multi:                    return \"multi\"\n            case .GenerateText:             return \"text\"\n            case .DeleteByToken:            return \"delete_by_token\"\n            }\n        }\n    }\n    \n    // MARK: - Public\n        \n    internal func setBackgroundCompletionHandler(_ newValue: (() -> ())?) {\n        networkAdapter.setBackgroundCompletionHandler(newValue)\n    }\n    \n    internal func setMaxConcurrentDownloads(_ maxConcurrentDownloads: Int) {\n        networkAdapter.setMaxConcurrentDownloads(maxConcurrentDownloads)\n    }\n\n    internal func setExtraHeaders(_ extraHeaders: [String: String]) {\n        self.extraHeaders = extraHeaders\n    }\n\n    internal func getExtraHeaders() -> [String: String]? {\n        return extraHeaders\n    }\n}\n\nclass CLDDownloadCoordinator: CLDNetworkCoordinator {\n\n    static var enableCache = true\n\n    static var urlCache = URLCache.init(memoryCapacity: Defines.defaultMaxMemoryCapacity, diskCapacity: Defines.defaultMaxDiskCapacity, diskPath: \"\")\n\n    init(configuration: CLDConfiguration) {\n\n        let downloadConfiguration                   = URLSessionConfiguration.default\n        downloadConfiguration.httpAdditionalHeaders = CLDNSessionManager.defaultHTTPHeaders\n        downloadConfiguration.urlCache              = CLDDownloadCoordinator.urlCache\n\n        let downloadAdapter = CLDDefaultNetworkAdapter(configuration: downloadConfiguration)\n        \n        super.init(configuration: configuration, networkAdapter: downloadAdapter)\n\n    }\n\n    override init(configuration: CLDConfiguration, sessionConfiguration: URLSessionConfiguration) {\n        super.init(configuration: configuration, sessionConfiguration: sessionConfiguration)\n    }\n    \n    override init(configuration: CLDConfiguration, networkAdapter: CLDNetworkAdapter) {\n        super.init(configuration: configuration, networkAdapter: networkAdapter)\n    }\n    \n}\n\ninternal struct Defines {\n    static let defaultMaxMemoryCapacity    = 30 * 1024 * 1024   // 30 MB\n    static let defaultMaxDiskCapacity      = 150 * 1024 * 1024  // 150 MB\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Network/NetworkRequest/CLDAsyncNetworkUploadRequest.swift",
    "content": "//\n//  CLDAsyncNetworkUploadRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal class CLDAsyncNetworkUploadRequest: CLDNetworkDataRequest {\n    \n    \n    // Once a value is set it should not be overridden\n    internal var networkDataRequest: CLDNetworkDataRequest? {\n        didSet {\n            if networkDataRequest != nil {\n                closureQueue.isSuspended = false\n            }\n        }\n    }\n    \n    fileprivate let closureQueue: OperationQueue = {\n        let operationQueue = OperationQueue()\n        operationQueue.name = \"com.cloudinary.CLDAsyncNetworkUploadRequest\"\n        operationQueue.maxConcurrentOperationCount = 1\n        operationQueue.isSuspended = true\n        return operationQueue\n    }()\n    \n    \n    // MARK: - CLDNetworkDataRequest\n    \n    func resume() {\n        closureQueue.addOperation {\n            self.networkDataRequest?.resume()\n        }\n    }\n    \n    func suspend() {\n        closureQueue.addOperation {\n            self.networkDataRequest?.suspend()\n        }\n    }\n    \n    func cancel() {\n        closureQueue.addOperation {\n            self.networkDataRequest?.cancel()\n        }\n    }\n    \n    func response(_ completionHandler: ((_ response: Any?, _ error: NSError?) -> ())?) -> CLDNetworkRequest {\n        closureQueue.addOperation {\n            self.networkDataRequest?.response(completionHandler)\n        }\n        return self\n    }\n    \n    func progress(_ progress: ((Progress) -> Void)?) -> CLDNetworkDataRequest {\n        closureQueue.addOperation {\n            self.networkDataRequest?.progress(progress)\n        }        \n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Network/NetworkRequest/CLDErrorRequest.swift",
    "content": "//\n//  CLDRequestError.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n\n\nimport Foundation\n\n/// Represents a failure to create the request\ninternal class CLDRequestError: CLDFetchImageRequest {\n    \n    var error: Error\n    \n    // MARK: - Init\n    \n    init(error: Error) {\n        self.error = error\n    }\n    \n    // MARK: - CLDNetworkRequest\n    func resume() {\n    }\n    \n    func suspend() {\n    }\n    \n    func cancel() {        \n    }\n    \n    // MARK: - CLDNetworkDataRequest\n    \n    func progress(_ progress: ((Progress) -> Void)?) -> CLDNetworkDataRequest {\n        return self\n    }\n    \n    \n    func response(_ completionHandler: ((_ response: Any?, _ error: NSError?) -> ())?) -> CLDNetworkRequest {\n        completionHandler?(nil, error as NSError?)\n        return self\n    }\n    \n    // MARK: - CLDFetchImageRequest\n    \n    func responseImage(_ completionHandler: CLDCompletionHandler?) -> CLDFetchImageRequest {\n        completionHandler?(nil, error as NSError?)\n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Network/NetworkRequest/CLDGenericNetworkRequest.swift",
    "content": "//\n//  CLDGenericNetworkRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal class CLDGenericNetworkRequest<T: CLDNRequest>: NSObject, CLDNetworkRequest {\n    \n    internal let request: T\n    \n    // MARK: - Init\n    \n    internal init(request: T) {\n        self.request = request\n    }\n    \n    //MARK: - State\n    \n    /**\n    Resume the current request.\n    */\n    func resume() {\n        request.resume()\n    }\n    \n    /**\n     Suspend the current request.\n     */\n    func suspend() {\n        request.suspend()\n    }\n    \n    /**\n     Cancel the current request.\n     */\n    func cancel() {\n        request.cancel()\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Network/NetworkRequest/CLDNetworkDataRequestImpl.swift",
    "content": "//\n//  CLDDataNetworkRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal class CLDNetworkDataRequestImpl<T: CLDNDataRequest>: CLDGenericNetworkRequest<T>, CLDNetworkDataRequest {\n    \n    @discardableResult\n    public func progress(_ progress: ((Progress) -> Void)?) -> CLDNetworkDataRequest {\n        if let progress = progress{\n            request.downloadProgress(closure: progress)\n        }\n        \n        return self\n    }\n    \n    //MARK: - Handlers\n    \n    func response(_ completionHandler: ((_ response: Any?, _ error: NSError?) -> ())?) -> CLDNetworkRequest {\n        \n        request.responseJSON { response in\n            if let value = response.result.value as? [String : AnyObject] {\n                if var error = value[\"error\"] as? [String : AnyObject] {\n                    let code = response.response?.statusCode ?? CLDError.CloudinaryErrorCode.generalErrorCode.rawValue\n                    error[\"statusCode\"] = code as AnyObject\n                    let err = CLDError.error(code: code, userInfo: error)\n                    completionHandler?(nil, err)\n                }\n                else {\n                    completionHandler?(value as AnyObject?, nil)\n                }\n            }\n            else if let err = response.result.error {\n                let error = err as NSError\n                completionHandler?(nil, error)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n            \n        }\n        \n        return self\n    }\n}\n\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Network/NetworkRequest/CLDNetworkDownloadRequest.swift",
    "content": "//\n//  CLDNetworkDownloadRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal class CLDNetworkDownloadRequest: CLDNetworkDataRequestImpl<CLDNDataRequest>, CLDFetchImageRequest {\n\n    //MARK: - Handlers\n    func responseImage(_ completionHandler: CLDCompletionHandler?) -> CLDFetchImageRequest {\n        \n        return responseData { (responseData, error, statusCode) -> () in\n            if let data = responseData {\n                if let image = data.cldToUIImageThreadSafe() {\n                    completionHandler?(image, nil)\n                }\n                else {\n                    let error = CLDError.error(code: .failedCreatingImageFromData, message: \"Failed creating an image from the received data.\", userInfo: [\"statusCode\": statusCode])\n                    completionHandler?(nil, error)\n                }\n            }\n            else if let err = error {\n                completionHandler?(nil, err)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError(userInfo: [\"statusCode\": statusCode]))\n            }\n        } as! CLDFetchImageRequest\n    }\n    \n    // MARK: - Private\n    @discardableResult\n    internal func responseData(_ completionHandler: ((_ responseData: Data?, _ error: NSError?, _ httpCode: Int?) -> ())?) -> CLDNetworkDataRequest {\n        request.responseData { response in\n            let statusCode = response.response?.statusCode\n            if let downloadedData = response.result.value {\n                if let statusCode = statusCode, self.isAcceptableCode(code: statusCode) {\n                    if CLDDownloadCoordinator.enableCache,\n                       let result = response.response,\n                       let data = response.data,\n                       let request = self.request.request,\n                       CLDDownloadCoordinator.urlCache.cachedResponse(for: request) == nil {\n                        let cachedData = CachedURLResponse(response: result, data: data)\n                        CLDDownloadCoordinator.urlCache.storeCachedResponse(cachedData, for: request)\n                    }\n                    completionHandler?(downloadedData, nil, statusCode)\n                }\n                else {\n                    let statusCodeError = CLDError.error(code: .unacceptableStatusCode, message: \"request error - unacceptable statusCode - \\(statusCode)\", userInfo: [\"statusCode\": statusCode])\n                    completionHandler?(downloadedData, statusCodeError, statusCode)\n                }\n            }\n            else if let err = response.result.error {\n                let error = err as NSError\n                completionHandler?(nil, error, statusCode)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError(userInfo: [\"statusCode\": statusCode]), statusCode)\n            }\n        }\n        return self\n    }\n    \n    func isAcceptableCode(code: Int) -> Bool {\n        self.request.acceptableStatusCodes.contains(code)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Network/NetworkRequest/CLDNetworkUploadRequest.swift",
    "content": "//\n//  CLDNetworkUploadRequest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal class CLDNetworkUploadRequest: CLDNetworkDataRequestImpl<CLDNUploadRequest> {\n    \n    override func progress(_ progress: ((Progress) -> Void)?) -> CLDNetworkDataRequest {\n        \n        if let progress = progress{\n            request.uploadProgress(closure: progress)\n        }\n        \n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Network/PrivacyInfo.xcprivacy",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>NSPrivacyAccessedAPITypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>NSPrivacyAccessedAPITypeReasons</key>\n\t\t\t<array>\n\t\t\t\t<string>0A2A.1</string>\n\t\t\t</array>\n\t\t\t<key>NSPrivacyAccessedAPIType</key>\n\t\t\t<string>NSPrivacyAccessedAPICategoryFileTimestamp</string>\n\t\t</dict>\n\t</array>\n\t<key>NSPrivacyCollectedDataTypes</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>NSPrivacyCollectedDataTypePurposes</key>\n\t\t\t<array>\n\t\t\t\t<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>\n\t\t\t</array>\n\t\t\t<key>NSPrivacyCollectedDataType</key>\n\t\t\t<string>NSPrivacyCollectedDataTypeAudioData</string>\n\t\t\t<key>NSPrivacyCollectedDataTypeTracking</key>\n\t\t\t<false/>\n\t\t\t<key>NSPrivacyCollectedDataTypeLinked</key>\n\t\t\t<true/>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>NSPrivacyCollectedDataTypePurposes</key>\n\t\t\t<array>\n\t\t\t\t<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>\n\t\t\t</array>\n\t\t\t<key>NSPrivacyCollectedDataType</key>\n\t\t\t<string>NSPrivacyCollectedDataTypeOtherUserContent</string>\n\t\t\t<key>NSPrivacyCollectedDataTypeTracking</key>\n\t\t\t<false/>\n\t\t\t<key>NSPrivacyCollectedDataTypeLinked</key>\n\t\t\t<true/>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>NSPrivacyCollectedDataTypePurposes</key>\n\t\t\t<array>\n\t\t\t\t<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>\n\t\t\t\t<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>\n\t\t\t</array>\n\t\t\t<key>NSPrivacyCollectedDataTypeTracking</key>\n\t\t\t<false/>\n\t\t\t<key>NSPrivacyCollectedDataTypeLinked</key>\n\t\t\t<true/>\n\t\t\t<key>NSPrivacyCollectedDataType</key>\n\t\t\t<string>NSPrivacyCollectedDataTypePhotosorVideos</string>\n\t\t</dict>\n\t</array>\n\t<key>NSPrivacyTrackingDomains</key>\n\t<array/>\n\t<key>NSPrivacyTracking</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Utils/CLDBuildParamsUtils.swift",
    "content": "//\n//  CLDBuildParamsUtils.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n\n// MARK: - Build String Params\n\ninternal func buildCoordinatesString(_ coordinates: [CLDCoordinate]) -> String {\n    return coordinates.map{$0.description}.joined(separator: \"|\")\n}\n\ninternal func buildEagerString(_ eager: [CLDTransformation]) -> String {\n    return eager.map {$0.asString() ?? \"\"}\n            .filter {!$0.isEmpty}\n            .joined(separator: \"|\")\n}\n\ninternal func buildContextString(_ context: [String : String]) -> String {\n    return context.map{\"\\($0)=\\(encodeContextValue($1))\"}.joined(separator: \"|\")\n}\n\ninternal func encodeContextValue(_ value: String) -> String {\n    return value.replacingOccurrences(of: \"|\", with: \"\\\\|\").replacingOccurrences(of: \"=\", with: \"\\\\=\")\n}\n\ninternal func buildHeadersString(_ headers: [String : String]) -> String {    \n    return headers.map{\"\\($0): \\($1)\\\\n\"}.joined(separator: \"\")\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Utils/CLDCryptoUtils.swift",
    "content": "//\n//  CLDCryptoUtils.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n\nimport Foundation\nimport CommonCrypto\n\npublic func cloudinarySignParamsUsingSecret(\n    _ paramsToSign: [String: Any],\n    cloudinaryApiSecret: String,\n    signatureVersion: Int? = 2\n) -> String {\n    let sortedKeys = paramsToSign.keys.sorted()\n    var paramsArr: [String] = []\n\n    for key in sortedKeys {\n        guard let value = paramsToSign[key],\n              let encodedValue = encodedParamValue(value) else {\n            continue\n        }\n        paramsArr.append(\"\\(key)=\\(encodedValue)\")\n    }\n\n    let toSign = paramsArr.joined(separator: \"&\")\n    return toSign.sha1_base8(cloudinaryApiSecret)\n}\n\nprivate func encodedParamValue(_ value: Any) -> String? {\n    var stringValue: String?\n\n    if let array = value as? [String], !array.isEmpty {\n        stringValue = array.joined(separator: \",\")\n    } else if let str = cldParamValueAsString(value: value) {\n        stringValue = str\n    }\n\n    guard let result = stringValue else {\n        return nil\n    }\n\n    return result.replacingOccurrences(of: \"&\", with: \"%26\")\n}\n\n\n\ninternal extension String {\n\n    func sha1_base8(_ secret: String?) -> String {\n        let data = self.data(using: String.Encoding.utf8)!\n        var digest = [UInt8](repeating: 0, count:Int(CC_SHA1_DIGEST_LENGTH))\n        let ctx = UnsafeMutablePointer<CC_SHA1_CTX>.allocate(capacity: 1)\n        CC_SHA1_Init(ctx)\n\n        _ = data.withUnsafeBytes { buffer in\n            CC_SHA1_Update(ctx, buffer.baseAddress!, CC_LONG(data.count))\n        }\n\n        if let secret = secret {\n            let secretData = secret.data(using: String.Encoding.utf8)!\n            _ = secretData.withUnsafeBytes { buffer in\n                CC_SHA1_Update(ctx, buffer.baseAddress!, CC_LONG(secretData.count))\n            }\n        }\n\n        CC_SHA1_Final(&digest, ctx)\n        let hexBytes = digest.map { String(format: \"%02hhx\", $0) }\n        return hexBytes.joined()\n    }\n\n    func sha1_base64() -> String {\n        return sha_base64(type: .sha1)\n    }\n    \n    func sha256_base64() -> String {\n        return sha_base64(type: .sha256)\n    }\n    \n    fileprivate func sha_base64(type: shaBase64Type) -> String {\n        var digest = [UInt8](repeating: 0, count:type.count)\n        type.hash(string: self, digest: &digest)\n        \n        let data = Data(bytes: digest, count: MemoryLayout<UInt8>.size * digest.count)\n        let base64 = data.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))\n        let encoded = base64.replacingOccurrences(of: \"/\", with: \"_\")\n                .replacingOccurrences(of: \"+\", with: \"-\")\n                .replacingOccurrences(of: \"=\", with: \"\")\n        \n        return encoded\n    }\n    \n    fileprivate enum shaBase64Type {\n        case sha1\n        case sha256\n        \n        var count: Int {\n            get {\n                switch self {\n                case .sha1  : return Int(CC_SHA1_DIGEST_LENGTH)\n                case .sha256: return Int(CC_SHA256_DIGEST_LENGTH)\n                }\n            }\n        }\n        \n        func hash(string: String, digest: UnsafeMutablePointer<UInt8>!) {\n        \n            let cStr = NSString(string: string).utf8String\n            \n            switch self {\n            case .sha1  : CC_SHA1(cStr, CC_LONG(strlen(cStr!)), digest)\n            case .sha256: CC_SHA256(cStr, CC_LONG(strlen(cStr!)), digest)\n            }\n        }\n    }\n\n    func toCRC32() -> UInt32 {\n        return crc32(self)\n    }\n    \n    func cld_md5() -> String {\n        var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))\n        if let data = self.data(using: String.Encoding.utf8) {\n            _ = data.withUnsafeBytes { buffer in\n                CC_MD5(buffer.baseAddress!, CC_LONG(buffer.count), &digest)\n            }\n        }\n        \n        var digestHex = \"\"\n        for index in 0..<Int(CC_MD5_DIGEST_LENGTH) {\n            digestHex += String(format: \"%02x\", digest[index])\n        }\n        \n        return digestHex\n    }\n}\n\nprivate func crc32(_ string: String) -> UInt32 {\n\n    let crcTable:[UInt32] = [0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,\n        0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,\n        0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,\n        0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,\n        0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,\n        0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,\n        0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,\n        0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,\n        0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,\n        0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,\n        0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,\n        0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,\n        0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,\n        0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,\n        0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,\n        0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,\n        0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,\n        0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,\n        0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,\n        0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,\n        0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,\n        0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,\n        0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,\n        0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,\n        0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,\n        0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,\n        0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,\n        0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,\n        0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,\n        0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,\n        0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,\n        0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d]\n    \n    \n    guard let data = string.data(using: String.Encoding.utf8)\n            else {\n        return 0\n    }\n\n    var crc:UInt32 = 0xffffffff\n    var buffer = (data as NSData).bytes.bindMemory(to: UInt8.self, capacity: data.count)\n\n    for _ in 1...data.count {\n        crc = (crc >> 8) ^ crcTable[Int((crc ^ UInt32(buffer.pointee)) & 0xff)]\n        buffer += 1\n    }\n\n    return crc ^ 0xffffffff\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Utils/CLDDictionaryUtils.swift",
    "content": "//\n//  CLDDictionaryUtils.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal extension Dictionary {\n    mutating func cldMerge(_ otherDictionary: Dictionary?) {\n        guard let otherDictionary = otherDictionary else {\n            return\n        }\n        for (key,value) in otherDictionary {\n            self.updateValue(value, forKey:key)\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Utils/CLDError.swift",
    "content": "//\n//  CLDError.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal struct CLDError {\n    \n    fileprivate static let domain = \"com.cloudinary.error\"\n    \n    enum CloudinaryErrorCode: Int {\n        case generalErrorCode                       = -7000\n        case failedCreatingImageFromData            = -7001\n        case failedDownloadingImage                 = -7002\n        case failedRetrievingFileInfo               = -7003\n        case preprocessingError                     = -7004\n        case failedDownloadingAsset                 = -7005\n        case unacceptableStatusCode                 = -7006\n    }\n    \n    static func generalError(userInfo: [AnyHashable: Any?]? = nil) -> NSError {\n        return error(code: .generalErrorCode, message: \"Something went wrong.\", userInfo: userInfo)\n    }\n    \n    static func error(domain: String = CLDError.domain, code: CloudinaryErrorCode, message: String) -> NSError {\n        let userInfo = [NSLocalizedFailureReasonErrorKey: message]\n        return error(domain: domain, code: code.rawValue, userInfo: userInfo)\n    }\n    \n    static func error(code: CloudinaryErrorCode, message: String, userInfo: [AnyHashable: Any?]?) -> NSError {\n        var _userInfo = userInfo\n        _userInfo?[NSLocalizedFailureReasonErrorKey] = message\n        return error(code: code.rawValue, userInfo: userInfo)\n    }\n    \n    static func error(domain: String? = CLDError.domain, code: Int, userInfo: [AnyHashable: Any?]?) -> NSError {\n        var info = [String: Any]()\n        var _domain = CLDError.domain\n        if let domain = domain {\n            _domain = domain\n        }\n        if let userInfo = userInfo {\n            userInfo.forEach {key, value in\n                if let value = value {\n                    info[String(describing: key)] = value\n                }\n                \n            }\n        }\n        \n        return NSError(domain: _domain, code: code, userInfo: info)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Utils/CLDFileUtils.swift",
    "content": "//\n//\n//  CLDFileUtils.swift\n//\n//  Copyright (c) 2017 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\nimport Foundation\n\ninternal class CLDFileUtils {\n    internal static func getFileSize(url: URL)->Int64?{\n        let attr = try? FileManager.default.attributesOfItem(atPath: url.path)\n        return attr?[FileAttributeKey.size] as? Int64\n    }\n\n    internal static func removeFile(file: URL) {\n        try? FileManager.default.removeItem(at: file)\n    }\n    \n\n    internal static func removeFiles(files: [CLDPartDescriptor]) {\n        for file in files {\n            removeFile (file: file.url)\n        }\n    }\n\n    internal static func splitFile(url: URL, chunkSize: Int) -> (URL?, [CLDPartDescriptor])?{\n        let maxBufferSize = 16 * 1024\n        var outputStream:OutputStream?\n        var success = false\n        var parts = [CLDPartDescriptor]()\n        guard let inputStream = InputStream(url: url) else {\n            return nil\n        }\n    \n        defer {\n            inputStream.close()\n            outputStream?.close()\n            \n            // clean up files if something failed mid-process\n            if (!success) {\n                removeFiles(files: parts)\n            }\n        }\n        \n        inputStream.open()\n        \n        let bufferSize = min(chunkSize, maxBufferSize)\n        var buffer = [UInt8](repeating: 0, count: bufferSize)\n        \n        var currentChunkBytes = 0\n        var chunkIndex = 0\n        var baseUrlResult = URL(fileURLWithPath: \"\")\n        var targetUrl = URL(fileURLWithPath:\"\")\n\n        var totalRead:Int64 = 0\n        let randomBaseFolder = NSUUID().uuidString\n        \n        while inputStream.hasBytesAvailable {\n            let read = inputStream.read(&buffer, maxLength: calcReadSize(currentChunkBytes, chunkSize, bufferSize))\n\n            if (read == 0) {\n                continue\n            }\n            \n            if (outputStream == nil){\n                (baseUrlResult, targetUrl) = getTempFileUrl(fileName: url.lastPathComponent, baseFolder: randomBaseFolder)\n                \n                outputStream = OutputStream(url: targetUrl, append: false)\n                \n                guard (outputStream != nil) else {\n                    return nil\n                }\n                \n                outputStream?.open()\n            }\n    \n            currentChunkBytes += read\n            totalRead += Int64(read)\n            outputStream!.write(&buffer, maxLength: read)\n            \n            if (currentChunkBytes >= chunkSize) {\n                // wrap up current chunk:\n                outputStream?.close()\n                outputStream = nil\n                parts.append(CLDPartDescriptor(url: targetUrl, offset: totalRead - Int64(currentChunkBytes), length: currentChunkBytes))\n                currentChunkBytes = 0\n                chunkIndex += 1\n            }\n        }\n        \n        if (outputStream != nil) {\n            // wrap up last chunk's last chunk:\n            parts.append(CLDPartDescriptor(url: targetUrl, offset: totalRead - Int64(currentChunkBytes), length: currentChunkBytes))\n        }\n        \n        success = true\n        return (baseUrlResult, parts)\n    }\n    \n    fileprivate static func calcReadSize(_ currentChunkBytes: Int, _ chunkSize: Int, _ bufferSize: Int) -> Int {\n        let chunkSpaceLeft = chunkSize - currentChunkBytes\n        let maxLength = min(bufferSize, chunkSpaceLeft)\n        return maxLength\n    }\n\n    internal static func getTempFileUrl(fileName: String, baseFolder: String) -> (URL, URL) {\n        let randomId = NSUUID().uuidString\n        let baseUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(baseFolder)\n        let tempDirURL = baseUrl.appendingPathComponent(randomId)\n        \n        try! FileManager.default.createDirectory(at: tempDirURL, withIntermediateDirectories: true, attributes: nil)\n    \n        return (baseUrl, tempDirURL.appendingPathComponent(fileName))\n    }\n}\n\npublic struct CLDPartDescriptor {\n    public let url: URL\n    public let offset: Int64\n    public let length: Int\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Utils/CLDImageGenerator/CLDImageGenerator.swift",
    "content": "//\n//  CLDImageGenerator.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport UIKit\n\n// MARK: - CLDImageDrawingInstructions\nprotocol CLDImageDrawingInstructions {\n    \n    var targetSize: CGSize { get }\n    func draw(in context: CGContext)\n}\n\n// MARK: - CLDImageGenerator\nclass CLDImageGenerator: NSObject {\n    \n    class CLDGeneratableImage {\n        \n        let instructions: CLDImageDrawingInstructions\n        \n        init(_ drawingInstructions: CLDImageDrawingInstructions) {\n            self.instructions = drawingInstructions\n        }\n        \n        /// Draws an image according to instructions\n        final func draw() -> UIImage? {\n            \n            UIGraphicsBeginImageContextWithOptions(instructions.targetSize, false, UIScreen.main.scale)\n            \n            guard let context = UIGraphicsGetCurrentContext() else { return nil }\n            \n            context.saveGState()\n            instructions.draw(in: context)\n            context.restoreGState()\n            \n            guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return nil }\n            \n            UIGraphicsEndImageContext()\n            \n            return image\n        }\n    }\n    \n    /// Generates an image based on an instructions object\n    ///\n    /// - Parameter instructions: Drawing instructions used to generate an image\n    /// - Parameter direction       : The direction of the generated image\n    static func generateImage(from instructions: CLDImageDrawingInstructions, for direction: CLDImageGenerator.Direction = .up) -> UIImage? {\n        \n        guard let workImage = CLDGeneratableImage(instructions).draw() else { return nil }\n        \n        return UIImage(cgImage: workImage.cgImage!, scale: workImage.scale, orientation: direction.imageOrientation)\n    }\n}\n\n// MARK: - CLDImageGenerator\nextension CLDImageGenerator {\n    \n    enum Direction: Int {\n        \n        case left\n        case right\n        case up\n        case down\n    }\n}\n\n// MARK: - CLDImageGenerator.Direction\nextension CLDImageGenerator.Direction {\n    \n    var imageOrientation: UIImage.Orientation {\n        \n        switch self {\n        case .up   : return .up\n        case .down : return .down\n        case .left : return .left\n        case .right: return .right\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Utils/CLDImageUtils.swift",
    "content": "//\n//  CLDImageUtils.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport UIKit\n\nprivate let lock = NSLock()\n\ninternal extension Data {\n    func cldToUIImageThreadSafe() -> UIImage? {\n        lock.lock()\n        let image = UIImage(data: self)\n        lock.unlock()\n        return image\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Utils/CLDJsonUtils.swift",
    "content": "//\n//  CLDJsonUtils.swift\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal func fromJson<T:Decodable>(object: [String: String]) -> T? {\n    if let jsonData = try? JSONSerialization.data(withJSONObject: object),\n       let object = try? getJsonDecoder().decode(T.self, from: jsonData) {\n        return object\n    }\n\n    return nil\n}\n\ninternal func asJsonArray<T:Encodable>(arr: [T]) -> String {\n    return \"[\\(arr.map {asJson(object: $0)}.joined(separator: \",\"))]\"\n}\n\ninternal func asJson<T:Encodable>(object: T) -> String {\n    return String(data: try! getJsonEncoder().encode(object), encoding: String.Encoding.utf8)!\n}\n\nfileprivate func getJsonDecoder() -> JSONDecoder {\n    let jsonDecoder = JSONDecoder()\n    jsonDecoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.formatted(getDateFormatter())\n    return jsonDecoder\n}\n\nfileprivate func getJsonEncoder() -> JSONEncoder {\n    let jsonEncoder = JSONEncoder()\n    jsonEncoder.dateEncodingStrategy = .formatted(getDateFormatter())\n    return jsonEncoder\n}\n\nfileprivate func getDateFormatter() -> DateFormatter {\n    let iso8601Formatter = DateFormatter()\n    iso8601Formatter.calendar = Calendar(identifier: .iso8601)\n    iso8601Formatter.locale = Locale(identifier: \"en_US_POSIX\")\n    iso8601Formatter.dateFormat = \"yyyy-MM-dd'T'HH:mm:ssXXXX\"\n    iso8601Formatter.timeZone = TimeZone(secondsFromGMT: 0)\n    return iso8601Formatter\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Utils/CLDLogManager.swift",
    "content": "//\n//  CLDLogManager.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\nprivate let prefix = \"[Cloudinary]\"\n\n@objc public enum CLDLogLevel: Int {\n    case trace, debug, info, warning, error, none\n}\n\nprivate enum LevelText: String {\n    case Trace, Debug, Info, Warning, Error, None\n}\n\nprivate func levelTextForLevel(_ logLevel: CLDLogLevel) -> LevelText {\n    switch(logLevel) {\n        case .trace:    return .Trace\n        case .debug:    return .Debug\n        case .info:     return .Info\n        case .warning:  return .Warning\n        case .error:    return .Error\n        case .none:     return .None\n    }\n}\n\ninternal struct CLDLogManager {\n    \n    internal static var minimumLogLevel = CLDLogLevel.none\n    \n}\n\n\ninternal func printLog<T>(_ logLevel : CLDLogLevel, text: T, _ file: String = #file, _ function: String = #function, _ line: Int = #line){\n    \n    if CLDLogManager.minimumLogLevel.rawValue <= logLevel.rawValue {\n        let filename = (file as NSString).lastPathComponent\n        let levelText = levelTextForLevel(logLevel).rawValue\n        print(\"\\(prefix):[\\(levelText)]: \\(filename).\\(function)[\\(line)]: \\(text)\")\n    }\n}\n\n"
  },
  {
    "path": "Cloudinary/Classes/Core/Utils/CLDStringUtils.swift",
    "content": "//\n//  CLDStringUtils.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\n\n//internal extension Int {\n//    func format(f: String) -> String {\n//        return String(format: \"%\\(f)d\", self)\n//    }\n//}\n\ninternal extension Double {\n    func cldFormat(f: String) -> String {\n        return String(format: \"%\\(f)f\", self)\n    }\n}\n\ninternal extension Float {\n    \n    func cldFloatFormat() -> String {\n        return cldFormat(f: \".1\")\n    }\n    \n    func cldFormat(f: String) -> String {\n        return String(format: \"%\\(f)f\", self)\n    }\n\n    /**\n        Returns an string using int format if the float is an integer value or the\n        full float if it isn't:\n        23.5 => \"23.5\"\n        23.5123 => \"23.5123\"\n        23 => \"23\"\n    */\n    func cldCleanFormat() -> String {\n        return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: \"%.0f\", self) : String(self);\n    }\n}\n\ninternal extension String {\n    func cldBase64Encode() -> String {\n        return (self.data(using: String.Encoding.utf8)?.base64EncodedString())!\n    }\n\n    func cldBase64UrlEncode() -> String {\n        return cldBase64Encode().replacingOccurrences(of: \"+\", with: \"-\").replacingOccurrences(of: \"/\", with: \"_\")\n    }\n    func cldSmartEncodeUrl() -> String? {\n        let customAllowedSet =  NSCharacterSet(charactersIn:\"!*'\\\"();@&=+$,?%#[] \").inverted\n        return addingPercentEncoding(withAllowedCharacters: customAllowedSet)\n    }\n    \n    subscript (i: Int) -> Character {\n        return self[startIndex.cldAdvance(i, for: self)]\n    }\n\n    subscript (r: CountableClosedRange<Int>) -> String {\n        get {\n            let startIndex =  self.index(self.startIndex, offsetBy: r.lowerBound)\n            let endIndex = self.index(startIndex, offsetBy: r.upperBound - r.lowerBound)\n            return String(self[startIndex...endIndex])\n        }\n    }  \n    \n    func cldStringByAppendingPathComponent(str: String) -> String {\n        return self + (\"/\\(str)\")\n    }\n    \n    func cldAsBool() -> Bool {\n        if self == \"true\" {\n            return true\n        }\n        if let intValue = Int(self) {\n            return NSNumber(value: intValue).boolValue\n        }\n        return false\n    }\n    \n    func cldAsNSNumber() -> NSNumber? {\n        if let intValue = Int(self) {\n            return NSNumber(value: intValue)\n        }\n        return nil\n    }\n    \n    func cldIsRemoteUrl() -> Bool {\n        return self.range(of: \"^ftp:|^https?:|^s3:|^gs:|^data:([\\\\w-]+\\\\/[\\\\w-]+(\\\\+[\\\\w-]+)?)?(;[\\\\w-]+=[\\\\w-]+)*;base64,([a-zA-Z0-9\\\\/+\\\\n=]+)$\", options: [NSString.CompareOptions.regularExpression, NSString.CompareOptions.caseInsensitive], range: nil, locale: nil) != nil\n    }\n\n    func leftPadding(toLength: Int, withPad character: Character) -> String {\n        let newLength = self.count\n        if newLength < toLength {\n            return String(repeatElement(character, count: toLength - newLength)) + self\n        } else {\n            return self.substring(from: index(self.startIndex, offsetBy: newLength - toLength))\n        }\n    }\n\n    func toAnalyticsVersionStr() -> String {\n        guard let binaryInt = UInt32(self, radix: 2) else {\n            return \"\"\n        }\n        switch binaryInt {\n        case 0..<25:\n            guard let value = UnicodeScalar(UnicodeScalar(\"A\").value + binaryInt) else {\n                return \"\"\n            }\n            return String(UnicodeScalar(value))\n        case 26..<51:\n            guard let value = UnicodeScalar(UnicodeScalar(\"a\").value + binaryInt - 26) else {\n                return \"\"\n            }\n            return String(UnicodeScalar(value))\n        default:\n            guard let value = UnicodeScalar(UnicodeScalar(\"0\").value + binaryInt - 52) else {\n                return \"\"\n            }\n            return String(UnicodeScalar(value))\n        }\n    }\n}\n\ninternal extension String.Index{\n//    func successor(in string:String)->String.Index{\n//        return string.index(after: self)\n//    }\n//\n//    func predecessor(in string:String)->String.Index{\n//        return string.index(before: self)\n//    }\n    \n    func cldAdvance(_ offset:Int, `for` string:String)->String.Index{\n        return string.index(self, offsetBy: offset)\n    }\n}\n\ninternal func cldParamValueAsString(value: Any) -> String? {\n    if let valueStr = value as? String {\n        if valueStr.isEmpty {\n            return nil\n        }\n        return valueStr\n    }\n    else if let valueNum = value as? NSNumber {\n        return String(describing: valueNum)\n    }\n    else {\n        printLog(.error, text: \"The parameter value must ba a String or a Number\")\n        return nil\n    }\n}\n\nextension String {\n    \n    internal func removePrefix(_ prefix: String) -> String {\n        guard self.hasPrefix(prefix) else { return self }\n        return String(self.dropFirst(prefix.count))    \n    }\n    \n    internal func firstIndex(of value: String) -> Int {\n        \n        guard let range: Range<String.Index> = range(of: value) else { return NSNotFound }\n        return distance(from: startIndex, to: range.lowerBound)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Extensions/CLDTransformation+Ios.swift",
    "content": "//\n//  CLDTransformation+Ios.swift\n//  Cloudinary\n//\n//  Created on 23/02/2020.\n//\n\nimport Foundation\nimport UIKit\n\nextension CLDTransformation\n{\n    /**\n     Deliver the image in the correct device pixel ratio, according to the used device.\n     \n     - returns:             The same instance of CLDTransformation.\n     */\n    @discardableResult\n    open func setDprAuto() -> Self {\n        let scale = Float(UIScreen.main.scale)\n        return setDpr(scale)\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Extensions/ExtensionCLDDownloader.swift",
    "content": "//\n//  ExtensionCLDDownloader.swift\n//\n//  Copyright (c) 2021 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\nextension CLDDownloader\n{\n    // MARK: - Actions\n    /**\n     Asynchronously fetches a remote image from the specified URL.\n     The image is retrieved from the cache if it exists, otherwise its downloaded and cached.\n     //TODO: REMOVE!!!\n     - parameter url:                    The image URL to download.\n     - parameter progress:          The closure that is called periodically during the data transfer.\n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the retrieved UIImage or the error.\n     \n     - returns:              A `CLDFetchImageRequest` instance to be used to get the fetched image from, or to get the download progress or cancel the task.\n     */\n    @discardableResult\n    open func fetchImage(_ url: String, _ progress: ((Progress) -> Void)? = nil, completionHandler: CLDCompletionHandler? = nil) -> CLDFetchImageRequest {\n        let request = CLDFetchImageRequestImpl(url: url, downloadCoordinator: downloadCoordinator)\n        request.responseImage(completionHandler)\n        request.progress(progress)\n        request.fetchImage()\n        return request\n    }\n    \n    /**\n     Asynchronously fetches a remote asset from the specified URL.\n     The asset is retrieved from the cache if it exists, otherwise its downloaded and cached.\n     \n     - parameter url:                    The asset URL to download.\n     - parameter progress:               The closure that is called periodically during the data transfer.\n     - parameter completionHandler:      The closure to be called once the request has finished, holding either the retrieved Data or an error.\n     \n     - returns:              A `CLDFetchAssetRequest` instance to be used to get the fetched image from, or to get the download progress or cancel the task.\n     */\n    @discardableResult\n    open func fetchAsset(_ url: String, _ progress: ((Progress) -> Void)? = nil, completionHandler: CLDAssetCompletionHandler? = nil) -> CLDFetchAssetRequest {\n        \n        let request = CLDFetchAssetRequestImpl(url: url, downloadCoordinator: downloadCoordinator)\n        request.responseAsset(completionHandler)\n        request.progress(progress)\n        request.fetchAsset()\n        return request\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Extensions/UIButton+Cloudinary.swift",
    "content": "//\n//  UIButton+Cloudinary.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport UIKit\n\npublic extension UIButton {\n    \n    /**\n     Download an image asynchronously from the specified URL and set it to the UIButton's image.\n     The image is retrieved from the cache if it exists, otherwise its downloaded and cached.\n     \n     - parameter url:               The image URL to download.\n     - parameter state:             The UIButton's UIControlState state that uses the specified image.\n     - parameter placeholder:       A placeholder image to be set as the image untill the asynchronus download request finishes.\n     \n     */\n    @objc func cldSetImage(_ url: String, forState state: UIControl.State, cloudinary: CLDCloudinary, placeholder: UIImage? = nil) {\n        fetchImageForUIElement(url, placeholder: placeholder, cloudinary: cloudinary) { [weak self] (image: UIImage) in\n            self?.setImage(image, for: state)\n        }\n    }\n    \n    /**\n     Download an image asynchronously from the specified URL and set it to the UIButton's image.\n     The image is retrieved from the cache if it exists, otherwise its downloaded and cached.\n     \n     - parameter publicId:          The remote asset's name (e.g. the public id of an uploaded image).\n     - parameter cloudinary:        An instance of CLDCloudinary.\n     - parameter state:             The UIButton's UIControlState state that uses the specified image.\n     - parameter signUrl:           A boolean parameter indicating whether or not to generate a signiture out of the API secret and add it to the generated URL. Default is false.\n     - parameter transformation:    An instance of CLDTransformation.\n     - parameter placeholder:       A placeholder image to be set as the background image untill the asynchronus download request finishes.\n     \n     */\n    @objc func cldSetImage(publicId: String, cloudinary: CLDCloudinary, forState state: UIControl.State, signUrl: Bool = false, transformation: CLDTransformation? = nil, placeholder: UIImage? = nil) {\n        \n        let urlGen = cloudinary.createUrl()\n        \n        if let transformation = transformation {\n            urlGen.setTransformation(transformation)\n        }\n        \n        guard let url = urlGen.generate(publicId, signUrl: signUrl) else {\n            if let placeholder = placeholder {\n                DispatchQueue.main.async { [weak self] in\n                    self?.setImage(placeholder, for: state)\n                }\n            }\n            \n            return\n        }\n        \n        fetchImageForUIElement(url, placeholder: placeholder, cloudinary: cloudinary) { [weak self] (image: UIImage) in\n            self?.setImage(image, for: state)\n        }\n    }\n    \n    /**\n     Download an image asynchronously from the specified URL and set it to the UIButton's background image.\n     The image is retrieved from the cache if it exists, otherwise its downloaded and cached.\n     \n     - parameter url:               The image URL to download.\n     - parameter state:             The UIButton's UIControlState state that uses the specified image.\n     - parameter placeholder:       A placeholder image to be set as the background image untill the asynchronus download request finishes.\n     \n    */\n    @objc func cld_setBackgroundImage(_ url: String, forState state: UIControl.State, cloudinary: CLDCloudinary, placeholder: UIImage? = nil) {\n        \n        let setImageOnMainQueue = { [weak self] (image: UIImage) in\n            DispatchQueue.main.async {\n                self?.setBackgroundImage(image, for: state)\n            }\n        }\n        \n        fetchImageForUIElement(url, placeholder: placeholder, cloudinary: cloudinary, fetchedImageHandler: setImageOnMainQueue)\n    }\n    \n    /**\n     Download an image asynchronously from the specified URL and set it to the UIButton's image.\n     The image is retrieved from the cache if it exists, otherwise its downloaded and cached.\n     \n     - parameter publicId:          The remote asset's name (e.g. the public id of an uploaded image).\n     - parameter cloudinary:        An instance of CLDCloudinary.\n     - parameter state:             The UIButton's UIControlState state that uses the specified image.\n     - parameter signUrl:           A boolean parameter indicating whether or not to generate a signiture out of the API secret and add it to the generated URL. Default is false.\n     - parameter transformation:    An instance of CLDTransformation.\n     - parameter placeholder:       A placeholder image to be set as the background image untill the asynchronus download request finishes.\n     \n     */\n    @objc func cld_setBackgroundImage(publicId: String, cloudinary: CLDCloudinary, forState state: UIControl.State, signUrl: Bool = false, transformation: CLDTransformation? = nil, placeholder: UIImage? = nil) {\n        \n        let urlGen = cloudinary.createUrl()\n        \n        if let transformation = transformation {\n            urlGen.setTransformation(transformation)\n        }\n        \n        guard let url = urlGen.generate(publicId, signUrl: signUrl) else {\n            if let placeholder = placeholder {\n                DispatchQueue.main.async { [weak self] in\n                    self?.setBackgroundImage(placeholder, for: state)\n                }\n            }\n            return\n        }\n        \n        fetchImageForUIElement(url, placeholder: placeholder, cloudinary: cloudinary) { [weak self] (image: UIImage) in\n            self?.setBackgroundImage(image, for: state)\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Extensions/UIImageView+Cloudinary.swift",
    "content": "//\n//  UIImageView+Cloudinary.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport UIKit\n\npublic extension UIImageView {\n    \n    /**\n     Download an image asynchronously from the specified URL and set it to the UIImageView's image.\n     The image is retrieved from the cache if it exists, otherwise its downloaded and cached.\n     \n     - parameter url:               The image URL to download.\n     - parameter cloudinary:        An instance of CLDCloudinary.\n     - parameter placeholder:       A placeholder image to be set as the background image untill the asynchronus download request finishes.\n     \n     */\n    @objc func cldSetImage(_ url: String, cloudinary: CLDCloudinary, placeholder: UIImage? = nil) {\n        fetchImageForUIElement(url, placeholder: placeholder, cloudinary: cloudinary) { [weak self] (image: UIImage) in\n            self?.image = image\n        }\n    }\n    \n    /**\n     Download an image asynchronously from the specified URL and set it to the UIImageView's image.\n     The image is retrieved from the cache if it exists, otherwise its downloaded and cached.\n     \n     - parameter publicId:          The remote asset's name (e.g. the public id of an uploaded image).\n     - parameter cloudinary:        An instance of CLDCloudinary.\n     - parameter signUrl:           A boolean parameter indicating whether or not to generate a signature out of the API secret and add it to the generated URL. Default is false.\n     - parameter resourceType       The resource type of the image to download (can be useful to display video frames for thumbnails).\n     - parameter transformation:    An instance of CLDTransformation.\n     - parameter placeholder:       A placeholder image to be set as the background image until the asynchronus download request finishes.\n     \n     */\n    @objc func cldSetImage(publicId: String, cloudinary: CLDCloudinary, signUrl: Bool = false, resourceType:CLDUrlResourceType = CLDUrlResourceType.image, transformation: CLDTransformation? = nil, placeholder: UIImage? = nil) {\n        var cloudinary = cloudinary\n        cloudinary.config.analyticsObject.setFeatureFlag(flag: \"E\")\n        let urlGen = cloudinary.createUrl()\n        \n        if let transformation = transformation {\n            urlGen.setTransformation(transformation)\n        }\n        \n        guard let url = urlGen.setResourceType(resourceType).generate(publicId, signUrl: signUrl) else {\n            if let placeholder = placeholder {\n                DispatchQueue.main.async { [weak self] in\n                    self?.image = placeholder\n                }\n            }\n            \n            return\n        }\n\n        fetchImageForUIElement(url, placeholder: placeholder, cloudinary: cloudinary) { [weak self] (image: UIImage) in\n            self?.image = image\n        }\n    }\n    \n    /**\n     Static var used to generate a unique address for the associated object\n     */\n    private struct AssociatedKeys {\n        static var cldCurrentUrl = \"cldCurrentUrl\"\n    }\n    \n    /**\n     Add an associated object to UIImageView so we can track the current url 'attached' to the image view.\n     This is important in case the view is used in an collection adapter where views are recycled, to verify\n     that when the async download finishes the associated url hasn't changed\n    */\n    internal var cldCurrentUrl:String? {\n        get {\n            return objc_getAssociatedObject(self, &AssociatedKeys.cldCurrentUrl) as? String\n        }\n        set {\n            objc_setAssociatedObject(self,  &AssociatedKeys.cldCurrentUrl, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Extensions/UIView+Cloudinary.swift",
    "content": "//\n//  UIView+Cloudinary.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport UIKit\n\ninternal extension UIView {    \n    func fetchImageForUIElement(_ url: String, placeholder: UIImage?, cloudinary: CLDCloudinary, fetchedImageHandler: @escaping ((_ fetchedImage: UIImage) -> ())) {\n        if let placeholder = placeholder {\n            fetchedImageHandler(placeholder)\n        }\n        \n        DispatchQueue.main.async {\n            self.setInProgressUrl(url)\n        }\n        \n        cloudinary.createDownloader().fetchImage(url, completionHandler:  { [weak self] (responseImage, error) in\n            if let img = responseImage {\n                DispatchQueue.main.async {\n                    if let view = self, view.isUrlStillRelevant(url) {\n                        fetchedImageHandler(img)\n                    }\n                }\n            }\n        })\n    }\n    \n    // set a url as the current request url for this view, if possible\n    func setInProgressUrl(_ url: String?){\n        // The associated propery `cldCurrentUrl` is only available on UIImageViews.\n        if let imageView = self as? UIImageView {\n            imageView.cldCurrentUrl = url\n        }\n    }\n    \n    // check whether the url is in sync with the last request url on this view, if possible\n    func isUrlStillRelevant(_ url: String) -> Bool {\n        // The associated property `cldCurrentUrl` is only available on UIImageViews,\n        // we do not store the url for other UIViews\n        if let imageView = self as? UIImageView, let lastRequestUrl = imageView.cldCurrentUrl {\n            return url == lastRequestUrl\n        }\n        \n        return true\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/NetworkRequest/CLDFetchAssetRequestImpl.swift",
    "content": "//\n//  CLDFetchAssetRequestImpl.swift\n//\n//  Copyright (c) 2021 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\n\ninternal class CLDFetchAssetRequestImpl: CLDFetchAssetRequest {\n    \n    fileprivate let url                : String\n    fileprivate let downloadCoordinator: CLDDownloadCoordinator\n    \n    fileprivate let closureQueue: OperationQueue\n    \n    fileprivate var data : Data?\n    fileprivate var error: NSError?\n    \n    // Requests\n    fileprivate var dataDownloadRequest: CLDNetworkDownloadRequest?\n    fileprivate var progress           : ((Progress) -> Void)?\n    \n    init(url: String, downloadCoordinator: CLDDownloadCoordinator) {\n        self.url = url\n        self.downloadCoordinator = downloadCoordinator\n        closureQueue = {\n            let operationQueue = OperationQueue()\n            operationQueue.name = \"com.cloudinary.CLDFetchAssetRequest\"\n            operationQueue.maxConcurrentOperationCount = 1\n            operationQueue.isSuspended = true\n            return operationQueue\n            }()\n    }\n    \n    // MARK: - Actions\n    func fetchAsset() {\n        DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async {\n            self.downloadData()\n        }\n    }\n    \n    // MARK: Private\n    fileprivate func downloadData() {\n        \n        dataDownloadRequest = downloadCoordinator.download(url) as? CLDNetworkDownloadRequest\n        dataDownloadRequest?.progress(progress)\n        \n        dataDownloadRequest?.responseData { [weak self] (responseData, responseError, statusCode) -> () in\n            if let data = responseData,\n               let err = responseError {\n                self?.data  = data\n                self?.error = err\n            }\n            else if let data = responseData {\n                self?.data = data\n            }\n            else if let err = responseError {\n                self?.error = err\n            }\n            else {\n                let error = CLDError.error(code: .failedDownloadingAsset, message: \"Failed attempting to download asset.\", userInfo: [\"statusCode\": statusCode])\n                self?.error = error\n            }\n            self?.closureQueue.isSuspended = false\n        }\n    }\n    \n    // MARK: - CLDFetchDataRequest\n    @discardableResult\n    @objc func responseAsset(_ completionHandler: CLDAssetCompletionHandler?) -> CLDFetchAssetRequest {\n        closureQueue.addOperation {\n            \n            if let data = self.data,\n               let error = self.error {\n                completionHandler?(data, error)\n            }\n            else if let data = self.data {\n                completionHandler?(data, nil)\n            }\n            else if let error = self.error {\n                completionHandler?(nil, error)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n        }\n        return self\n    }\n    \n    @discardableResult\n    @objc func progress(_ progress: ((Progress) -> Void)?) -> CLDNetworkDataRequest {\n        if let downloadRequest = self.dataDownloadRequest {\n            downloadRequest.progress(progress)\n        }\n        else {\n            self.progress = progress\n        }\n        return self\n    }\n    \n    @objc func resume() {\n        dataDownloadRequest?.resume()\n    }\n    \n    @objc func suspend() {\n        dataDownloadRequest?.suspend()\n    }\n    \n    \n    @objc func cancel() {\n        dataDownloadRequest?.cancel()\n    }\n    \n    @objc func response(_ completionHandler: ((_ response: Any?, _ error: NSError?) -> ())?) -> CLDNetworkRequest {\n        responseAsset(completionHandler)\n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/NetworkRequest/CLDFetchImageRequestImpl.swift",
    "content": "//\n//  CLDFetchImageRequestImpl.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport UIKit\n\ninternal class CLDFetchImageRequestImpl: CLDFetchImageRequest {\n    \n    fileprivate let url: String\n    fileprivate let downloadCoordinator: CLDDownloadCoordinator\n    \n    fileprivate let closureQueue: OperationQueue\n    \n    fileprivate var image: UIImage?\n    fileprivate var error: NSError?\n    \n    \n    // Requests\n    fileprivate var imageDownloadRequest: CLDNetworkDownloadRequest?\n    fileprivate var progress: ((Progress) -> Void)?\n    \n    init(url: String, downloadCoordinator: CLDDownloadCoordinator) {\n        self.url = url\n        self.downloadCoordinator = downloadCoordinator\n        closureQueue = {\n            let operationQueue = OperationQueue()\n            operationQueue.name = \"com.cloudinary.CLDFetchImageRequest\"\n            operationQueue.maxConcurrentOperationCount = 1\n            operationQueue.isSuspended = true\n            return operationQueue\n        }()\n    }\n    \n    // MARK: - Actions\n    \n    func fetchImage() {\n        DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async {\n            self.downloadImageAndCacheIt()\n        }\n    }\n    \n    // MARK: Private\n    fileprivate func downloadImageAndCacheIt() {\n        imageDownloadRequest = downloadCoordinator.download(url) as? CLDNetworkDownloadRequest\n        imageDownloadRequest?.progress(progress)\n\n        imageDownloadRequest?.responseData { [weak self] (responseData, responseError, httpCode) -> () in\n            if let data = responseData, let\n                image = data.cldToUIImageThreadSafe(),\n               let url = self?.url {\n                self?.image = image\n            } else if let err = responseError {\n                self?.error = err\n            }\n            else {\n                let error = CLDError.error(code: .failedDownloadingImage, message: \"Failed attempting to download image.\", userInfo: [\"statusCode\": httpCode])\n                self?.error = error\n            }\n            self?.closureQueue.isSuspended = false\n        }\n    }\n    \n    // MARK: - CLDFetchImageRequest\n    \n    @discardableResult\n    @objc func responseImage(_ completionHandler: CLDCompletionHandler?) -> CLDFetchImageRequest {\n        closureQueue.addOperation {\n            if let image = self.image {\n                completionHandler?(image, nil)\n            }\n            else if let error = self.error {\n                completionHandler?(nil, error)\n            }\n            else {\n                completionHandler?(nil, CLDError.generalError())\n            }\n        }\n        return self\n    }\n    \n    @discardableResult\n    @objc func progress(_ progress: ((Progress) -> Void)?) -> CLDNetworkDataRequest {\n        if let downloadRequest = self.imageDownloadRequest {\n            downloadRequest.progress(progress)\n        }\n        else {\n            self.progress = progress\n        }\n        return self\n    }\n    \n    @objc func resume() {\n        imageDownloadRequest?.resume()\n    }\n    \n    @objc func suspend() {\n        imageDownloadRequest?.suspend()\n    }\n    \n    \n    @objc func cancel() {\n        imageDownloadRequest?.cancel()\n    }\n    \n    @objc func response(_ completionHandler: ((_ response: Any?, _ error: NSError?) -> ())?) -> CLDNetworkRequest {\n        responseImage(completionHandler)\n        return self\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/UIViews/CLDResponsiveViewHelper.swift",
    "content": "//\n//  CLDResponsiveViewHelper.swift\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport UIKit\n\n@objcMembers open class CLDResponsiveViewHelper : NSObject{\n    fileprivate var requestedWidth = 0\n    fileprivate var requestedHeight = 0\n    fileprivate var viewSizeKnown = false\n    \n    fileprivate var publicId: String!\n    fileprivate var cloudinary: CLDCloudinary!\n    fileprivate var signUrl: Bool!\n    fileprivate var resourceType:CLDUrlResourceType!\n    fileprivate var responsiveParams : CLDResponsiveParams?\n    fileprivate var baseTransformation: String?\n    fileprivate var placeholder: UIImage?\n    \n    public func cldSetImage(view: UIImageView, publicId: String, cloudinary: CLDCloudinary, signUrl: Bool = false, resourceType: CLDUrlResourceType = CLDUrlResourceType.image,\n                                  responsiveParams: CLDResponsiveParams, transformation: CLDTransformation? = nil, placeholder: UIImage? = nil) {\n        self.publicId = publicId\n        self.signUrl = signUrl\n        self.cloudinary = cloudinary\n        self.resourceType = resourceType\n        self.responsiveParams = responsiveParams\n        self.baseTransformation = transformation?.asString()\n        self.placeholder = placeholder\n        \n        if (viewSizeKnown){\n            doResponsive(view)\n        }\n    }\n    \n    open func onViewSizeKnown(view: UIImageView) {\n        viewSizeKnown = true\n        \n        // if no one called cldSetImage we have nothing to do here\n        if let params = responsiveParams {\n            // We fetch an image in two cases: 1) This is the first time, or 2) The view got larger and the deverloper requested to reload the image on resize.\n            if (requestedWidth == 0 && requestedHeight == 0) ||\n                (params.shouldReloadOnSizeChange && didGetLarger(view)) {\n                doResponsive(view)\n            }\n        }\n    }\n    \n    fileprivate func didGetLarger(_ view: UIImageView) -> Bool {\n        return getRoundedContentHeight(view) > requestedHeight || getRoundedContentWidth(view) > requestedWidth\n    }\n    \n    fileprivate func doResponsive(_ view: UIImageView){\n        // Only fetch an image of a responsive transformation was generated successfully:\n        if let transformation = self.chainResponsiveTransformation(view) {\n            view.cldSetImage(publicId: publicId, cloudinary: cloudinary, signUrl: signUrl, resourceType: resourceType, transformation: transformation, placeholder: placeholder)\n        }\n    }\n    \n    fileprivate func chainResponsiveTransformation(_ view: UIImageView) -> CLDTransformation? {\n        guard view.bounds.width > 0 && view.bounds.height > 0 else {\n            // nothing to do\n            return nil\n        }\n        \n        let params = responsiveParams!\n        let responsiveTransformation = CLDTransformation()\n        \n        if let baseTransformation = baseTransformation {\n                responsiveTransformation.setRawTransformation(baseTransformation).chain()\n        }\n        \n        if (params.autoWidth) {\n            requestedWidth = getRoundedContentWidth(view)\n            responsiveTransformation.setWidth(requestedWidth)\n        } else {\n            requestedWidth = 0\n        }\n        \n        if (params.autoHeight) {\n            requestedHeight = getRoundedContentHeight(view)\n            responsiveTransformation.setHeight(requestedHeight)\n        } else {\n            requestedHeight = 0\n        }\n        \n        if let crop = params.cropMode {\n            responsiveTransformation.setCrop(crop)\n        }\n        \n        if let gravity = params.gravity {\n            responsiveTransformation.setGravity(gravity)\n        }\n        \n        return responsiveTransformation.setDpr(Float(UIScreen.main.scale))\n    }\n    \n    fileprivate func getRoundedContentHeight(_ view: UIImageView) -> Int {\n        return trimAndRoundUp(Int(round(view.frame.height - view.layoutMargins.top - view.layoutMargins.bottom)))\n    }\n    \n    fileprivate func getRoundedContentWidth(_ view: UIImageView) -> Int {\n        return trimAndRoundUp(Int(round(view.frame.width - view.layoutMargins.left - view.layoutMargins.right)))\n    }\n    \n    fileprivate func trimAndRoundUp(_ dimension: Int) -> Int {\n        let value = ((dimension - 1) / responsiveParams!.stepSizePoints + 1) * responsiveParams!.stepSizePoints;\n        return max(responsiveParams!.minDimensionPoints, min(value, responsiveParams!.maxDimensionPoints));\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/UIViews/CLDUIImageView.swift",
    "content": "//\n//  CLDUIImageView.swift\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n\nimport UIKit\n\n@objcMembers open class CLDUIImageView: UIImageView {\n    // Delegate most of the logic to a helper instance. To use responsive downloads in situations\n    // where one cannot use CLDUIImageView a CLDResponsiveViewHelper can be used in any other custom UIVIew\n    // as long as these two methods are used.\n    internal let responsiveHelper: CLDResponsiveViewHelper = CLDResponsiveViewHelper()\n\n    /**\n     Download an image asynchronously from the specified URL and set it to the UIImageView's image.\n     The image is retrieved from the cache if it exists, otherwise its downloaded and cached. Note: this must be used on the main thread.\n     \n     - parameter publicId:          The remote asset's name (e.g. the public id of an uploaded image).\n     - parameter cloudinary:        An instance of CLDCloudinary.\n     - parameter signUrl:           A boolean parameter indicating whether or not to generate a signature out of the API secret and add it to the generated URL. Default is false.\n     - parameter resourceType       The resource type of the image to download (can be useful to display video frames for thumbnails).\n     - parameter responsiveParams   An instance of CLDResponsiveParams to configure fetching a pre-scaled image to fit in the UIImageView.\n     - parameter transformation:    An instance of CLDTransformation.\n     - parameter placeholder:       A placeholder image to be set as the background image until the asynchronus download request finishes.\n     \n     */\n    @objc public func cldSetImage(publicId: String, cloudinary: CLDCloudinary, signUrl: Bool = false, resourceType: CLDUrlResourceType = CLDUrlResourceType.image,\n                                  responsiveParams: CLDResponsiveParams, transformation: CLDTransformation? = nil, placeholder: UIImage? = nil) {\n\n        responsiveHelper.cldSetImage (view: self, publicId: publicId, cloudinary: cloudinary, signUrl: signUrl, resourceType: resourceType, responsiveParams: responsiveParams, transformation : transformation, placeholder: placeholder)\n    }\n\n    override open func layoutSubviews() {\n        super.layoutSubviews()\n\n        if (bounds.width > 0 && bounds.height > 0) {\n            // notify the delegate that the view now knows it's own size\n            responsiveHelper.onViewSizeKnown(view: self)\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Uploader/CLDImagePreprocessChain.swift",
    "content": "//\n//\n//  CLDImagePreprocessChain.swift\n//\n//  Copyright (c) 2017 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport UIKit\n\n/**\n The CLDImagePreprocessChain is used to run preprocessing on images before uploading.\n It support processing, validations and encoders, all fully customizable.\n*/\npublic class CLDImagePreprocessChain: CLDPreprocessChain<UIImage> {\n    public override init() {\n    }\n\n    internal override func decodeResource(_ resourceData: Any) throws -> UIImage? {\n        if let url = resourceData as? URL {\n            if let resourceData = try? Data(contentsOf: url) {\n                return UIImage(data: resourceData)\n            }\n        } else if let data = resourceData as? Data {\n            return UIImage(data: data)\n        }\n\n        return nil\n    }\n\n    internal override func verifyEncoder() throws {\n        if (encoder == nil) {\n            setEncoder(CLDPreprocessHelpers.defaultImageEncoder)\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Uploader/CLDPreprocessHelpers.swift",
    "content": "//\n//\n//  CLDPreprocessHelpers.swift\n//\n//  Copyright (c) 2017 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n\nimport Foundation\nimport UIKit\n\n/**\n This class contains ready-to-use encoders and processing steps to be used with CLDPreprocessChain\n */\npublic class CLDPreprocessHelpers {\n    \n    static let defaultImageEncoder: CLDResourceEncoder<UIImage> = CLDPreprocessHelpers.customImageEncoder(format: EncodingFormat.PNG, quality: 100)\n    \n    /**\n     Get a CLDPreprocessStep closure to send to CLDPreprocessChain. Scales down any image larger than width/height\n     params while retaining the original aspect ratio. If the original image is already within bounds it will be\n     returned unchanged (i.e. a smaller image won't be enlarged).\n     \n     - parameter width:             Maximum allowed width\n     - parameter height:            Maximum allowed height\n     \n     - returns:                     A closure to use in a preprocessing chain.\n     */\n    public static func limit(width: CGFloat, height: CGFloat) -> CLDPreprocessStep<UIImage> {\n        \n        return { image in\n            \n            if (image.size.width > width || image.size.height > height) {\n                return resizeImage(image: image, requiredSize: CGSize(width: width, height: height))\n            }\n            return image\n        }\n    }\n    \n    /**\n     Get a CLDPreprocessStep closure to send to CLDPreprocessChain. Returns the image cropped to the requested rectangle. This step will validate that the chosen rectangle is within the image's dimensions, otherwise an exception is thrown and the CLDUploadRequest fails.\n     \n     - parameter cropRect:          The requested crop rectangle.\n     \n     - returns:                     A closure to use in a preprocessing chain.\n     */\n    public static func crop(cropRect: CGRect) -> CLDPreprocessStep<UIImage> {\n        \n        return { image in\n            \n            let imageRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)\n            guard imageRect.contains(cropRect) else {\n                throw CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"Crop dimensions out of bounds\")\n            }\n            \n            if let croppedImage = image.cld_crop(cropRect) {\n                return croppedImage\n            }\n            else {\n                throw CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"Image cropping failed\")\n            }\n        }\n    }\n    /**\n     Get a CLDPreprocessStep closure to send to CLDPreprocessChain. Rotates any image to the requested degree.\n     \n     - parameter degrees:           The requested rotation degree\n     \n     - returns:                     A closure to use in a preprocessing chain.\n     */\n    public static func rotate(degrees: Float) -> CLDPreprocessStep<UIImage> {\n        \n        return { image in\n            \n            if let rotatedImage = image.cld_rotate(degrees) {\n                return rotatedImage\n            }\n            return image\n        }\n    }\n    \n    /**\n     Get a CLDResourceEncoder to use in CLDPreprocessChain. This encoder saves the image with the\n     chosen format and quality.\n     \n     - parameter format:   Image format to encode the image\n     - parameter quality:  Quality to save the image (ignored if the chosen\n     format doesn't support quality)\n     \n     - returns:            A closure to use as encoder in a preprocessing chain\n     */\n    public static func customImageEncoder(format: EncodingFormat, quality: CGFloat) -> CLDResourceEncoder<UIImage> {\n        \n        return { image in\n            \n            if let data = encodeAs(image: image, format: format, quality: quality) {\n                \n                let (_, url) = CLDFileUtils.getTempFileUrl(fileName: NSUUID().uuidString, baseFolder:\"imageEncoder\")\n                try? data.write(to: url)\n                return url\n                \n            }\n            return nil\n        }\n    }\n    \n    /**\n     Get a CLDPreprocessStep to send to CLDPreprocessChain. This step will validate that a given image's\n     dimensions are within the chosen bounds, otherwise an exception is throw and the CLDUploadRequest fails.\n     \n     - parameter minWidth:         Minimum width allowed.\n     - parameter maxWidth:         Maximum width allowed.\n     - parameter minHeight:        Minimum height allowed.\n     - parameter maxHeight:        Maximum height allowed.\n     \n     - returns:                     A closure to use in a preprocessing chain.\n     */\n    public static func dimensionsValidator(minWidth: Int, maxWidth: Int, minHeight: Int, maxHeight: Int) -> CLDPreprocessStep<UIImage> {\n        \n        return { image in\n            \n            if let width = image.cgImage?.width, let height = image.cgImage?.height {\n                if (width  > maxWidth  || width  < minWidth ||\n                    height > maxHeight || height < minHeight) {\n                    throw CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"Image dimensions invalid\")\n                }\n            }\n            return image\n        }\n    }\n    \n    internal static func encodeAs(image: UIImage, format: EncodingFormat, quality: CGFloat) -> Data? {\n        \n        switch format {\n        case EncodingFormat.JPEG:\n            return image.jpegData(compressionQuality: quality)\n        case EncodingFormat.PNG:\n            return image.pngData()\n        }\n    }\n    \n    internal static func resizeImage(image: UIImage, requiredSize: CGSize) -> UIImage {\n        \n        let widthRatio = requiredSize.width / image.size.width\n        let heightRatio = requiredSize.height / image.size.height\n        \n        let newSize: CGSize\n        if (heightRatio > widthRatio) {\n            newSize = CGSize(width: requiredSize.width, height: round(widthRatio * image.size.height))\n        } else {\n            newSize = CGSize(width: round(heightRatio * image.size.width), height: requiredSize.height)\n        }\n        \n        var newImage: UIImage\n        \n        UIGraphicsBeginImageContextWithOptions(CGSize(width: newSize.width, height: newSize.height), false, 1.0)\n        image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))\n        newImage = UIGraphicsGetImageFromCurrentImageContext()!\n        UIGraphicsEndImageContext()\n        \n        return newImage\n    }\n}\n\ninternal extension UIImage\n{\n    func cld_crop(_ rect: CGRect) -> UIImage? {\n        \n        UIGraphicsBeginImageContextWithOptions(rect.size, false, self.scale)\n        self.draw(at: CGPoint(x: -rect.origin.x, y: -rect.origin.y))\n        let croppedImage = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        return croppedImage\n    }\n    \n    fileprivate func cld_radians(from degrees: Double) -> CGFloat {\n        return CGFloat(degrees * Double.pi / 180.0);\n    }\n    \n    func cld_rotate(_ degree: Float) -> UIImage? {\n        var newSize = CGRect(origin: CGPoint.zero, size: self.size).applying(CGAffineTransform(rotationAngle: cld_radians(from: Double(degree)))).size\n        // Trim off the extremely small float value to prevent core graphics from rounding it up\n        newSize.width = floor(newSize.width)\n        newSize.height = floor(newSize.height)\n        \n        UIGraphicsBeginImageContextWithOptions(newSize, false, self.scale)\n        let context = UIGraphicsGetCurrentContext()!\n        \n        // Move origin to middle\n        context.translateBy(x: newSize.width/2, y: newSize.height/2)\n        // Rotate around middle\n        context.rotate(by: cld_radians(from: Double(degree)))\n        // Draw the image at its center\n        draw(in: CGRect(x: -self.size.width/2, y: -self.size.height/2, width: self.size.width, height: self.size.height))\n        \n        let newImage = UIGraphicsGetImageFromCurrentImageContext()\n        UIGraphicsEndImageContext()\n        \n        return newImage\n    }\n}\n\npublic enum EncodingFormat {\n    case JPEG\n    case PNG\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Uploader/CLDVideoPreprocessChain.swift",
    "content": "//\n//  CLDVideoPreprocessChain.swift\n//\n//  Copyright (c) 2017 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport AVKit\n\npublic typealias CLDVideoPreprocessStep = (CLDVideoTranscode) throws -> CLDVideoTranscode\n\npublic class CLDVideoPreprocessChain: CLDPreprocessChain<CLDVideoTranscode> {\n    private var outputURL: URL?\n\n    public override init() {\n        super.init()\n    }\n\n    internal override func decodeResource(_ resourceData: Any) throws -> CLDVideoTranscode? {\n        if let url = resourceData as? URL {\n            return CLDVideoTranscode(sourceURL: url)\n        } else if let data = resourceData as? Data {\n            return try handleLargeVideoData(data)\n        } else {\n            throw CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"Resource type should be URL or Data only!\")\n        }\n    }\n\n    private func handleLargeVideoData(_ data: Data) throws -> CLDVideoTranscode? {\n        var tempDirectory: URL!\n        if #available(iOS 10.0, *) {\n            tempDirectory = FileManager.default.temporaryDirectory\n        } else {\n            tempDirectory = URL(fileURLWithPath: NSTemporaryDirectory())\n        }\n        let tempURL = tempDirectory.appendingPathComponent(UUID().uuidString).appendingPathExtension(\"mp4\")\n        do {\n            try data.write(to: tempURL)\n            return CLDVideoTranscode(sourceURL: tempURL)\n        } catch {\n            throw CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"Failed to write data to temporary file: \\(error.localizedDescription)\")\n        }\n    }\n\n    public func setOutputFormat(format: AVFileType) -> Self {\n        addStep { videoTranscode in\n            try videoTranscode.setOutputFormat(format: format)\n            return videoTranscode\n        }\n        return self\n    }\n\n    public func setOutputDimensions(dimensions: CGSize) -> Self {\n        addStep { videoTranscode in\n            videoTranscode.setOutputDimensions(dimensions: dimensions)\n            return videoTranscode\n        }\n        return self\n    }\n\n    public func setCompressionPreset(preset: String) -> Self {\n        addStep { videoTranscode in\n            videoTranscode.setCompressionPreset(preset: preset)\n            return videoTranscode\n        }\n        return self\n    }\n\n    internal override func execute(resourceData: Any) throws -> URL {\n        try verifyEncoder()\n\n        guard let videoTranscode = try decodeResource(resourceData) else {\n            throw CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"Error decoding resource\")\n        }\n\n        let dispatchGroup = DispatchGroup()\n        var resultURL: URL?\n        var resultError: Error?\n\n        dispatchGroup.enter()\n\n        DispatchQueue.global(qos: .background).async {\n            do {\n                var processedTranscode = videoTranscode\n                for preprocess in self.chain {\n                    processedTranscode = try preprocess(processedTranscode)\n                }\n\n                processedTranscode.transcode { success, error in\n                    if success, let outputURL = processedTranscode.outputURL {\n                        resultURL = outputURL\n                    } else {\n                        resultError = error ?? CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"Error transcoding video\")\n                    }\n                    dispatchGroup.leave()\n                }\n            } catch {\n                resultError = error\n                dispatchGroup.leave()\n            }\n        }\n\n        dispatchGroup.wait()\n\n        if let finalOutputURL = resultURL {\n            return finalOutputURL\n        } else {\n            throw resultError ?? CLDError.error(code: CLDError.CloudinaryErrorCode.preprocessingError, message: \"Unknown error\")\n        }\n    }\n\n    internal override func verifyEncoder() throws {\n        if encoder == nil {\n            encoder = { _ in self.outputURL }\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Uploader/CLDVideoPreprocessHelpers.swift",
    "content": "import Foundation\nimport AVKit\n\npublic class CLDVideoPreprocessHelpers {\n\n    private var steps: [(CLDVideoTranscode) throws -> CLDVideoTranscode] = []\n\n    public func addStep(_ step: @escaping (CLDVideoTranscode) throws -> CLDVideoTranscode) {\n        steps.append(step)\n    }\n\n    public static func setOutputFormat(format: AVFileType) -> CLDVideoPreprocessStep {\n        return { videoTranscode in\n            do {\n                try videoTranscode.setOutputFormat(format: format)\n            } catch {\n                throw error\n            }\n            return videoTranscode\n        }\n    }\n\n    public static func setOutputDimensions(dimensions: CGSize) -> CLDVideoPreprocessStep {\n        return { videoTranscode in\n            videoTranscode.setOutputDimensions(dimensions: dimensions)\n            return videoTranscode\n        }\n    }\n\n    public static func setCompressionPreset(preset: String) -> CLDVideoPreprocessStep {\n        return { videoTranscode in\n            videoTranscode.setCompressionPreset(preset: preset)\n            return videoTranscode\n        }\n    }\n\n    public static func dimensionsValidator(minWidth: CGFloat, maxWidth: CGFloat, minHeight: CGFloat, maxHeight: CGFloat) -> CLDVideoPreprocessStep {\n        return { videoTranscode in\n            guard let dimensions = videoTranscode.outputDimensions else {\n                throw NSError(domain: \"CLDVideoPreprocessHelpers\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"Dimensions not set\"])\n            }\n            if dimensions.width < minWidth || dimensions.width > maxWidth || dimensions.height < minHeight || dimensions.height > maxHeight {\n                throw VideoPreprocessError.dimensionsOutOfRange\n            }\n            return videoTranscode\n        }\n    }\n}\n\nenum VideoPreprocessError: Error {\n    case dimensionsOutOfRange\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Uploader/CLDVideoTranscode.swift",
    "content": "import Foundation\nimport AVFoundation\n\npublic class CLDVideoTranscode {\n    let sourceURL: URL\n    var outputURL: URL?\n    var outputFormat: AVFileType = .mov\n    var outputDimensions: CGSize?\n    var compressionPreset: String = AVAssetExportPresetPassthrough // Default to passthrough\n\n    init(sourceURL: URL) {\n        self.sourceURL = sourceURL\n    }\n\n    func setOutputFormat(format: AVFileType) throws {\n        guard FileManager.default.fileExists(atPath: sourceURL.path) else {\n            throw NSError(domain: \"CLDVideoPreprocessHelpers\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"Invalid source URL\"])\n        }\n\n        let asset = AVAsset(url: sourceURL)\n        guard asset.tracks(withMediaType: .video).first != nil else {\n            throw NSError(domain: \"CLDVideoPreprocessHelpers\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"No video track found\"])\n        }\n\n        self.outputFormat = format\n    }\n\n    func setOutputDimensions(dimensions: CGSize) {\n        self.outputDimensions = dimensions\n    }\n\n    func setCompressionPreset(preset: String) {\n        self.compressionPreset = preset\n    }\n\n    var hasVideoTrack: Bool {\n        let asset = AVAsset(url: sourceURL)\n        return asset.tracks(withMediaType: .video).first != nil\n    }\n\n    func transcode(completion: @escaping (Bool, Error?) -> Void) {\n        let asset = AVAsset(url: sourceURL)\n        let outputURL = generateOutputURL()\n\n        do {\n            // Create asset reader\n            let assetReader = try AVAssetReader(asset: asset)\n            guard let videoTrack = asset.tracks(withMediaType: .video).first else {\n                throw NSError(domain: \"CLDVideoTranscode\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"No video track found\"])\n            }\n\n            // Configure output settings for AVAssetReader\n            let assetReaderOutputSettings = [\n                kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32ARGB\n            ]\n\n            let assetReaderOutput = AVAssetReaderTrackOutput(track: videoTrack, outputSettings: assetReaderOutputSettings)\n\n            // Add the output to the reader\n            assetReader.add(assetReaderOutput)\n\n            // Create asset writer\n            let assetWriter = try AVAssetWriter(outputURL: outputURL, fileType: outputFormat)\n            let videoSettings: [String: Any] = [\n                AVVideoWidthKey: outputDimensions?.width ?? videoTrack.naturalSize.width,\n                AVVideoHeightKey: outputDimensions?.height ?? videoTrack.naturalSize.height\n            ]\n\n            let assetWriterInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)\n            assetWriterInput.expectsMediaDataInRealTime = true\n            assetWriter.add(assetWriterInput)\n\n            // Start reading and writing\n            assetReader.startReading()\n            assetWriter.startWriting()\n            assetWriter.startSession(atSourceTime: .zero)\n\n            assetWriterInput.requestMediaDataWhenReady(on: DispatchQueue(label: \"assetWriterQueue\")) {\n                while assetWriterInput.isReadyForMoreMediaData {\n                    guard assetReader.status == .reading else {\n                        let error = assetReader.error ?? NSError(domain: \"CLDVideoTranscode\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"Asset reader status is not reading\"])\n                        completion(false, error)\n                        return\n                    }\n\n                    if let sampleBuffer = assetReaderOutput.copyNextSampleBuffer() {\n                        assetWriterInput.append(sampleBuffer)\n                    } else {\n                        assetWriterInput.markAsFinished()\n                        assetWriter.finishWriting {\n                            defer {\n                                if self.sourceURL.isFileURL {\n                                    try? FileManager.default.removeItem(at: self.sourceURL)\n                                }\n                            }\n\n                            if assetWriter.status == .completed {\n                                self.outputURL = assetWriter.outputURL\n                                completion(true, nil)\n                            } else {\n                                completion(false, assetWriter.error)\n                            }\n                        }\n                        break\n                    }\n                }\n            }\n        } catch {\n            completion(false, error)\n        }\n    }\n\n    private func generateOutputURL() -> URL {\n        return URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString).appendingPathExtension(outputFormat.fileExtension)\n    }\n}\n\nprivate extension AVFileType {\n    var fileExtension: String {\n        switch self {\n        case .mov:\n            return \"mov\"\n        case .mp4:\n            return \"mp4\"\n        case .m4v:\n            return \"m4v\"\n        default:\n            return \"mov\"\n        }\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Video/Analytics/VideoAnalytics.swift",
    "content": "//\n//  VideoAnalytics.swift\n//  Cloudinary\n//\n//  Created by Adi Mizrahi on 14/12/2023.\n//\n\nimport Foundation\n\npublic typealias EventDetails = [String: Any]\ntypealias CustomerData = [String: Any]\ntypealias VideoData = [String: Any]\ntypealias ProvidedData = [String: Any]\n\npublic enum TrackingType: String {\n    case manual = \"manual\"\n    case auto = \"auto\"\n}\n\npublic enum PlayerKeyPath: String {\n    case status = \"status\"\n    case timeControlStatus = \"timeControlStatus\"\n    case duration = \"duration\"\n}\n\npublic enum AnalyticsType {\n    case auto\n    case manual\n    case disabled\n}\n\nstruct VideoPlayer {\n    var type: String\n    var version: String\n}\n\npublic class VideoEvent {\n    public var trackingType: TrackingType\n    public var eventName: String\n    public var eventTime: Int\n    public var eventDetails: EventDetails\n\n    init(trackingType: TrackingType, eventName: String, eventDetails: EventDetails? = nil) {\n        self.trackingType = trackingType\n        self.eventName = eventName\n        self.eventTime = Int(Int64((Date().timeIntervalSince1970 * 1000.0).rounded()))\n        self.eventDetails = eventDetails ?? [String: Any]()\n        self.eventDetails[VideoEventJSONKeys.videoPlayer.rawValue] = createVideoPlayerObject()\n    }\n\n    func createVideoPlayerObject() -> [String: Any] {\n        return [VideoEventJSONKeys.type.rawValue: \"ios_player\", VideoEventJSONKeys.version.rawValue: CLDNetworkCoordinator.DEFAULT_VERSION]\n    }\n\n    func createCustomerData(trackingData: [String: String]?, providedData: [String: Any]?) -> [String: Any] {\n        var videoData = VideoData()\n        videoData[VideoEventJSONKeys.cloudName.rawValue] = trackingData?[VideoEventJSONKeys.cloudName.rawValue] ?? \"\"\n        videoData[VideoEventJSONKeys.publicId.rawValue] = trackingData?[VideoEventJSONKeys.publicId.rawValue] ?? \"\"\n\n        var result: [String: Any] = [VideoEventJSONKeys.videoData.rawValue: videoData]\n\n        if let providedData = providedData, !providedData.isEmpty {\n            var providedDataObject = ProvidedData()\n            providedData.forEach { (key, value) in\n                providedDataObject[key] = value\n            }\n            result[VideoEventJSONKeys.providedData.rawValue] = providedDataObject\n        }\n\n        return result\n    }\n\n    func toDictonary() -> [String: Any] {\n        var detailsDictionary: [String: Any] = [:]\n\n        for (key, value) in eventDetails {\n            detailsDictionary[key] = value\n        }\n        return [\n            VideoEventJSONKeys.eventName.rawValue: eventName,\n            VideoEventJSONKeys.eventName.rawValue: eventTime,\n            VideoEventJSONKeys.eventDetails.rawValue: detailsDictionary\n        ]\n    }\n}\n\npublic class VideoViewStartEvent: VideoEvent {\n    public init(trackingType: TrackingType = .auto, videoUrl: String, trackingData: [String: String]?,providedData: [String: Any]? = nil) {\n        var eventDetails = EventDetails()\n        eventDetails[VideoEventJSONKeys.trackingType.rawValue] = trackingType.rawValue\n        eventDetails[VideoEventJSONKeys.videoUrl.rawValue] = videoUrl\n        let defaultEventName = EventNames.viewStart.rawValue\n        super.init(trackingType: trackingType, eventName: defaultEventName, eventDetails: eventDetails)\n        super.eventDetails[VideoEventJSONKeys.customerData.rawValue] = createCustomerData(trackingData: trackingData, providedData: providedData)\n    }\n}\n\npublic class VideoLoadMetadata: VideoEvent {\n    public init(trackingType: TrackingType = .auto, duration: Int, providedData: [String: Any]? = nil) {\n        var eventDetails = EventDetails()\n        eventDetails[VideoEventJSONKeys.trackingType.rawValue] = trackingType.rawValue\n        eventDetails[VideoEventJSONKeys.videoDuration.rawValue] = duration\n        let defaultEventName = EventNames.loadMetadata.rawValue\n        super.init(trackingType: trackingType, eventName: defaultEventName, eventDetails: eventDetails)\n    }\n}\n\npublic class VideoViewEnd: VideoEvent {\n    public init(trackingType: TrackingType = .auto, providedData: [String: Any]? = nil) {\n        var eventDetails = EventDetails()\n        eventDetails[VideoEventJSONKeys.trackingType.rawValue] = trackingType.rawValue\n        let defaultEventName = EventNames.viewEnd.rawValue\n        super.init(trackingType: trackingType, eventName: defaultEventName, eventDetails: eventDetails)\n    }\n}\n\npublic class VideoPlayEvent: VideoEvent {\n    public init(trackingType: TrackingType = .auto, providedData: [String: Any]? = nil) {\n        let defaultEventName = EventNames.play.rawValue\n        super.init(trackingType: trackingType, eventName: defaultEventName)\n    }\n}\n\npublic class VideoPauseEvent: VideoEvent {\n    public init(trackingType: TrackingType = .auto, providedData: [String: Any]? = nil) {\n        let defaultEventName = EventNames.pause.rawValue\n        super.init(trackingType: trackingType, eventName: defaultEventName)\n    }\n}\n\n\npublic enum VideoEventJSONKeys: String {\n    case userId = \"userId\"\n    case trackingType = \"trackingType\"\n    case viewId = \"viewId\"\n    case events = \"events\"\n    case eventName = \"eventName\"\n    case eventTime = \"eventTime\"\n    case eventDetails = \"eventDetails\"\n    case videoPlayer = \"videoPlayer\"\n    case videoUrl = \"videoUrl\"\n    case videoDuration = \"videoDuration\"\n    case videoPublicId = \"videoPublicId\"\n    case transformation = \"transfromation\"\n    case videoExtension = \"videoExtension\"\n    case customerData = \"customerData\"\n    case videoData = \"videoData\"\n    case providedData = \"providedData\"\n    case cloudName = \"cloudName\"\n    case publicId = \"publicId\"\n    case type = \"type\"\n    case version = \"version\"\n}\n\npublic enum EventNames: String {\n    case viewStart = \"viewStart\"\n    case viewEnd = \"viewEnd\"\n    case loadMetadata = \"loadMetadata\"\n    case play = \"play\"\n    case pause = \"pause\"\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Video/Analytics/VideoEventsManager.swift",
    "content": "//\n//  VideoEventsManager.swift\n//  Cloudinary\n//\n//  Created by Adi Mizrahi on 14/12/2023.\n//\n\nimport Foundation\n@objcMembers public class VideoEventsManager {\n\n    let CLD_ANALYTICS_ENDPOINT_PRODUCTION_URL: String = \"https://video-analytics-api.cloudinary.com/v1/video-analytics\"\n    public var CLD_ANALYTICS_ENDPOINT_DEVELOPMENT_URL = \"\"\n\n    var viewId: String\n\n    var userId: String!\n\n    var trackingType: TrackingType = .auto\n\n    var cloudName: String?\n\n    var publicId: String?\n\n    public init() {\n        viewId = UUID().uuidString.lowercased().replacingOccurrences(of: \"-\", with: \"\")\n        userId = getUserId()\n    }\n\n    func getUserId() -> String {\n        if let userId = UserDefaults.standard.string(forKey: \"CLDVideoPlayerUserId\") {\n            return userId\n        } else {\n            var newUserId = UUID().uuidString\n            newUserId = newUserId.lowercased().replacingOccurrences(of: \"-\", with: \"\")\n            UserDefaults.standard.set(newUserId, forKey: \"CLDVideoPlayerUserId\")\n            return newUserId\n        }\n    }\n\n    public func sendViewStartEvent(videoUrl: String, providedData: [String: Any]? = nil) {\n        let event = VideoViewStartEvent(trackingType: trackingType, videoUrl: videoUrl, trackingData: [\"cloudName\": cloudName ?? \"\", \"publicId\": publicId ?? \"\"], providedData: providedData)\n        addEventToQueue(event: event)\n    }\n\n    public func sendViewEndEvent(providedData: [String: Any]? = nil) {\n        let event = VideoViewEnd(trackingType: trackingType,  providedData: providedData)\n        addEventToQueue(event: event)\n    }\n\n    public func sendLoadMetadataEvent(duration: Int, providedData: [String: Any]? = nil) {\n        let event = VideoLoadMetadata(trackingType: trackingType, duration: duration, providedData: providedData)\n        addEventToQueue(event: event)\n    }\n\n    public func sendPlayEvent(providedData: [String: Any]? = nil) {\n        let event = VideoPlayEvent(trackingType: trackingType, providedData: providedData)\n        addEventToQueue(event: event)\n\n    }\n\n    public func sendPauseEvent(providedData: [String: Any]? = nil) {\n        let event = VideoPauseEvent(trackingType: trackingType, providedData: providedData)\n        addEventToQueue(event: event)\n    }\n\n    public var eventQueue = [VideoEvent]()\n    private var timer: Timer?\n\n    func addEventToQueue(event: VideoEvent) {\n        eventQueue.append(event)\n    }\n\n    @objc public func sendEvents() {\n        guard !eventQueue.isEmpty else {\n            return\n        }\n\n        let eventsToSend = Array(eventQueue.prefix(eventQueue.count))\n        sendEventToEndpoint(childEvents: eventsToSend)\n        eventQueue.removeFirst(eventsToSend.count)\n    }\n\n    private func buildFormDataPart(boundary: String, name: String, value: String? = nil) -> Data {\n        var body = Data()\n        body.append(contentsOf: \"--\\(boundary)\\r\\n\".utf8)\n        body.append(contentsOf: \"Content-Disposition: form-data; name=\\\"\\(name)\\\"\\r\\n\\r\\n\".utf8)\n        if let value = value {\n            body.append(contentsOf: \"\\(value)\\r\\n\".utf8)\n        }\n        return body\n    }\n\n    private func buildEventsData(childEvents: [VideoEvent]) -> Data? {\n        var body = Data()\n        var eventData: [[String: Any]] = []\n        for childEvent in childEvents {\n            eventData.append([\n                VideoEventJSONKeys.eventName.rawValue: childEvent.eventName,\n                VideoEventJSONKeys.eventTime.rawValue: childEvent.eventTime,\n                VideoEventJSONKeys.eventDetails.rawValue: childEvent.eventDetails])\n        }\n\n        do {\n            let jsonData = try JSONSerialization.data(withJSONObject: eventData, options: [])\n            body.append(jsonData)\n            body.append(contentsOf: \"\\r\\n\".utf8)\n            return body\n        } catch {\n            print(\"Error creating JSON data: \\(error)\")\n            return nil\n        }\n\n    }\n\n    private func sendEventToEndpoint(childEvents: [VideoEvent]) {\n        var request = URLRequest(url: URL(string: CLD_ANALYTICS_ENDPOINT_PRODUCTION_URL)!)\n        request.httpMethod = \"POST\"\n\n        let boundary = \"Boundary-\\(UUID().uuidString)\"\n        request.setValue(\"multipart/form-data; boundary=\\(boundary)\", forHTTPHeaderField: \"Content-Type\")\n        request.setValue(\"ios_video_player_analytics_test\", forHTTPHeaderField: \"User-Agent\")\n        var body = Data()\n\n        // Add events data\n        body.append(buildFormDataPart(boundary: boundary, name: \"userId\", value: userId))\n        body.append(buildFormDataPart(boundary: boundary, name: \"viewId\", value: viewId))\n        body.append(buildFormDataPart(boundary: boundary, name: \"events\"))\n        body.append(buildEventsData(childEvents: childEvents)!)\n        body.append(contentsOf: \"--\\(boundary)--\\r\\n\".utf8)\n        request.httpBody = body\n\n        URLSession.shared.dataTask(with: request) { data, response, error in\n            if let error = error {\n                print(\"Error sending event: \\(error)\")\n            } else if let httpResponse = response as? HTTPURLResponse,\n                      (200...299).contains(httpResponse.statusCode) {\n                print(\"Event sent successfully\")\n            } else {\n                print(\"Failed to send event. Response: \\(response.debugDescription)\")\n            }\n        }.resume()\n    }\n}\n"
  },
  {
    "path": "Cloudinary/Classes/ios/Video/CLDVideoPlayer.swift",
    "content": "//\n//  CLDVideoPlayer.swift\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport AVKit\n\n\n@available(iOS 10.0, *)\n@objcMembers open class CLDVideoPlayer: AVPlayer {\n\n    var automaticStreamingProfile: Bool = false\n\n    var analytics: Bool = true\n    var isIntialized: Bool = false\n    var loadMetadataSent: Bool = false\n\n    var publicId: String?\n\n    var transformation: CLDTransformation?\n\n    var eventsManager: VideoEventsManager = VideoEventsManager()\n\n    var providedData: [String: Any]?\n\n    override init() {\n        super.init()\n        setAnalyticsObservers()\n    }\n\n    /**\n     Download a video asynchronously from the specified URL and set it to the AVPlayer video.\n\n     - parameter publicId:                      The remote asset's name (e.g. the public id of an uploaded image).\n     - parameter cloudinary:                    An instance of CLDCloudinary.\n     - parameter transformation:                An instance of CLDTransformation.\n     - parameter automaticStreamingProfile:     A bool to indicate the use of automatic streaming profile default: false\n\n     */\n    public init(publicId: String, cloudinary: CLDCloudinary, transformation: CLDTransformation? = nil, automaticStreamingProfile: Bool? = false) {\n        var cloudinary = cloudinary\n        cloudinary.config.analyticsObject.setFeatureFlag(flag: \"F\")\n        var transformation = transformation\n        var cldUrl = cloudinary.createUrl()\n        if automaticStreamingProfile ?? false && transformation == nil {\n            cldUrl = cldUrl.setFormat(\"m3u8\")\n            transformation = CLDTransformation().setStreamingProfile(\"auto\")\n        }\n        guard let urlString = cldUrl.setResourceType(.video)\n            .setTransformation(transformation ?? CLDTransformation())\n            .generate(publicId), let url = URL(string: urlString) else {\n            print(\"Error - could not generate URL for CLDVideoPlayer\")\n            super.init()\n            return\n        }\n        super.init(url: url)\n    }\n\n    /**\n     Initializes a CLDVideoPlayer instance, using a given AVPlayerItem.\n\n     - parameter item:  The player item to put into AVPlayer\n\n     */\n    public override init(playerItem item: AVPlayerItem?) {\n        super.init(playerItem: item)\n    }\n\n    /**\n     Initializes a CLDVideoPlayer instance, using a given URL.\n\n     - parameter url:  The URL to put into AVPlayer\n\n     */\n    public override init(url URL: URL) {\n        super.init(url: URL)\n    }\n\n    /**\n     Initializes a CLDVideoPlayer instance, using a given URL.\n\n     - parameter url:  The string to put into AVPlayer\n\n     */\n    public init(url string: String) {\n        guard let url = URL(string: string) else {\n            print(\"Error - could not generate URL for CLDVideoPlayer\")\n            super.init()\n            return\n        }\n        super.init(url: url)\n    }\n\n    public func setAnalytics(_ analyticsType: AnalyticsType, cloudName: String?, publicId: String?) {\n        switch analyticsType {\n        case .auto:\n            eventsManager.trackingType = .auto\n            eventsManager.cloudName = cloudName ?? \"\"\n            eventsManager.publicId = publicId ?? self.publicId\n            break\n        case .manual:\n            eventsManager.trackingType = .manual\n            eventsManager.cloudName = cloudName ?? \"\"\n            eventsManager.publicId = publicId ?? self.publicId\n            break\n        case .disabled:\n            analytics = false\n        }\n    }\n\n    public func flushEvents() {\n        guard analytics else { return }\n        eventsManager.sendEvents()\n    }\n\n    public func flushEventsAndCloseSession() {\n        guard analytics else { return }\n        eventsManager.sendViewEndEvent(providedData: providedData)\n        flushEvents()\n    }\n\n    deinit {\n        guard analytics else { return }\n        removeObserver(self, forKeyPath: PlayerKeyPath.status.rawValue)\n        removeObserver(self, forKeyPath: PlayerKeyPath.timeControlStatus.rawValue)\n        flushEventsAndCloseSession()\n    }\n\n    func setAnalyticsObservers() {\n        guard analytics else {\n            return\n        }\n        addObserver(self, forKeyPath: PlayerKeyPath.status.rawValue, options: [.new], context: nil)\n        addObserver(self, forKeyPath: PlayerKeyPath.timeControlStatus.rawValue, options: [.new], context: nil)\n    }\n\n    open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {\n        guard let path = keyPath, let changes = change else {\n            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)\n            return\n        }\n\n        switch path {\n        case PlayerKeyPath.status.rawValue:\n            if let newStatusNumber = changes[.newKey] as? NSNumber, let newStatus = AVPlayer.Status(rawValue: newStatusNumber.intValue) {\n                handleStatusChanged(newStatus)\n            }\n        case PlayerKeyPath.timeControlStatus.rawValue:\n            if let newStatusNumber = changes[.newKey] as? NSNumber, let newStatus = AVPlayer.TimeControlStatus(rawValue: newStatusNumber.intValue) {\n                handleTimeControlStatusChanged(newStatus)\n            }\n        default:\n            super.observeValue(forKeyPath: path, of: object, change: changes, context: context)\n        }\n    }\n\n}\n\n@available(iOS 10.0, *)\nextension CLDVideoPlayer {\n    func handleStatusChanged(_ status: AVPlayer.Status) {\n        switch status {\n        case .readyToPlay:\n            if let assetURL = self.currentItem?.asset as? AVURLAsset {\n                let mediaURL = assetURL.url\n                eventsManager.sendViewStartEvent(videoUrl: mediaURL.absoluteString, providedData: providedData)\n                isIntialized = true\n\n                loadDurationAsynchronously()\n            }\n            break\n        case .failed:\n            // Playback failed\n            break\n        case .unknown:\n            // Unknown status\n            break\n        @unknown default:\n            break\n        }\n    }\n    \n    private func loadDurationAsynchronously() {\n        guard let currentItem = self.currentItem else { return }\n        \n        let asset = currentItem.asset\n        let durationKey = \"duration\"\n        \n        // Load the duration key asynchronously\n        asset.loadValuesAsynchronously(forKeys: [durationKey]) { [weak self] in\n            DispatchQueue.main.async {\n                guard let self = self else { return }\n                \n                var error: NSError?\n                let status = asset.statusOfValue(forKey: durationKey, error: &error)\n                \n                switch status {\n                case .loaded:\n                    let duration = asset.duration\n                    var durationInSeconds = 0\n                    \n                    if duration.isValid && duration.isNumeric && !duration.isIndefinite {\n                        let durationSeconds = CMTimeGetSeconds(duration)\n                        \n                        if durationSeconds.isFinite && !durationSeconds.isNaN {\n                            durationInSeconds = Int(durationSeconds)\n                        }\n                    }\n                    \n                    if !self.loadMetadataSent {\n                        self.loadMetadataSent = true\n                        self.eventsManager.sendLoadMetadataEvent(duration: durationInSeconds)\n                    }\n                case .failed, .cancelled:\n                    print(\"Failed to load duration: \\(error?.localizedDescription ?? \"Unknown error\")\")\n                case .loading:\n                    // Still loading, could retry or wait\n                    break\n                case .unknown:\n                    // Unknown status\n                    break\n                @unknown default:\n                    break\n                }\n            }\n        }\n    }\n\n    func handleTimeControlStatusChanged(_ status: AVPlayer.TimeControlStatus) {\n        switch status {\n        case .playing:\n            eventsManager.sendPlayEvent(providedData: providedData)\n        case .paused:\n            // Player paused\n            if isIntialized {\n                if self.timeControlStatus == .paused {\n                    eventsManager.sendPauseEvent(providedData: providedData)\n                }\n            }\n        case .waitingToPlayAtSpecifiedRate:\n            break\n        @unknown default:\n            break\n        }\n    }\n\n    public func setProvidedData(data: [String: Any]) {\n        providedData = data\n    }\n}\n"
  },
  {
    "path": "Cloudinary.podspec",
    "content": "#\n# Be sure to run `pod lib lint Cloudinary.podspec' to ensure this is a\n# valid spec before submitting.\n#\n# Any lines starting with a # are optional, but their use is encouraged\n# To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html\n#\n\nPod::Spec.new do |s|\n    s.name             = 'Cloudinary'\n    s.version          = '5.2.5'\n    s.summary          = \"Cloudinary is a cloud service that offers a solution to a web application's entire image management pipeline.\"\n    \n    s.description      = <<-DESC\n    Easily upload images to the cloud. Automatically perform smart image resizing, cropping and conversion without installing any complex software.\n    Integrate Facebook or Twitter profile image extraction in a snap, in any dimension and style to match your website’s graphics requirements.\n    Images are seamlessly delivered through a fast CDN, and much much more.\n    Cloudinary offers comprehensive APIs and administration capabilities and is easy to integrate with any web application, existing or new.\n    Cloudinary provides URL and HTTP based APIs that can be easily integrated with any Web development framework.\n    DESC\n    \n    s.homepage         = 'http://cloudinary.com'\n    s.license          = { :type => 'MIT', :file => 'LICENSE' }\n    s.author           = { \"Cloudinary\" => \"info@cloudinary.com\" }\n    s.source           = { :git => \"https://github.com/cloudinary/cloudinary_ios.git\", :tag => s.version.to_s }\n    \n    s.swift_version         = '5.0'\n    s.ios.deployment_target = '9.0'\n    s.frameworks            = 'UIKit', 'Foundation'\n    \n    s.default_subspec  = 'ios'\n    \n    s.subspec 'ios' do |spec|\n        \n        spec.platform              = :ios\n        spec.source_files          = 'Cloudinary/Classes/**/*.{swift,h}'\n        spec.resource_bundles      = { 'Cloudinary' => ['Cloudinary/Classes/Core/Network/PrivacyInfo.xcprivacy'] }\n\n    end\nend\n"
  },
  {
    "path": "Cloudinary.xcodeproj/Cloudinary_Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<plist version=\"1.0\">\n<dict>\n  <key>CFBundleDevelopmentRegion</key>\n  <string>en</string>\n  <key>CFBundleExecutable</key>\n  <string>$(EXECUTABLE_NAME)</string>\n  <key>CFBundleIdentifier</key>\n  <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n  <key>CFBundleInfoDictionaryVersion</key>\n  <string>6.0</string>\n  <key>CFBundleName</key>\n  <string>$(PRODUCT_NAME)</string>\n  <key>CFBundlePackageType</key>\n  <string>FMWK</string>\n  <key>CFBundleShortVersionString</key>\n  <string>1.0</string>\n  <key>CFBundleSignature</key>\n  <string>????</string>\n  <key>CFBundleVersion</key>\n  <string>$(CURRENT_PROJECT_VERSION)</string>\n  <key>NSPrincipalClass</key>\n  <string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Cloudinary.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\tB690BF5E2BC55992007117AC /* HTTPStatusCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B690BF5D2BC55992007117AC /* HTTPStatusCode.swift */; };\n\t\tB694AAEC2B308AF100075041 /* CLDAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B694AAEB2B308AF100075041 /* CLDAnalytics.swift */; };\n\t\tB694AAEF2B308B8400075041 /* VideoAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B694AAEE2B308B8400075041 /* VideoAnalytics.swift */; };\n\t\tB694AAF12B308B9D00075041 /* VideoEventsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B694AAF02B308B9D00075041 /* VideoEventsManager.swift */; };\n\t\tB6B4C49A2C560FEE00C9B604 /* CLDVideoPreprocessChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4C4992C560FEE00C9B604 /* CLDVideoPreprocessChain.swift */; };\n\t\tB6B4C49C2C56100600C9B604 /* CLDVideoTranscode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4C49B2C56100600C9B604 /* CLDVideoTranscode.swift */; };\n\t\tB6B4C4A12C5615CF00C9B604 /* CLDVideoPreprocessHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4C4A02C5615CF00C9B604 /* CLDVideoPreprocessHelpers.swift */; };\n\t\tB6C2D4862A724C4200AA0039 /* CLDVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C2D4852A724C4200AA0039 /* CLDVideoPlayer.swift */; };\n\t\tOBJ_257 /* CLDNConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* CLDNConvertible.swift */; };\n\t\tOBJ_258 /* CLDNError.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* CLDNError.swift */; };\n\t\tOBJ_259 /* CLDNMultipartFormData.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* CLDNMultipartFormData.swift */; };\n\t\tOBJ_260 /* CLDNParameterEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* CLDNParameterEncoding.swift */; };\n\t\tOBJ_261 /* CLDNRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_14 /* CLDNRequest.swift */; };\n\t\tOBJ_262 /* CLDNResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_15 /* CLDNResponse.swift */; };\n\t\tOBJ_263 /* CLDNResponseSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_16 /* CLDNResponseSerialization.swift */; };\n\t\tOBJ_264 /* CLDNResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_17 /* CLDNResult.swift */; };\n\t\tOBJ_265 /* CLDNSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* CLDNSessionDelegate.swift */; };\n\t\tOBJ_266 /* CLDNSessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_19 /* CLDNSessionManager.swift */; };\n\t\tOBJ_267 /* CLDNTaskDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_20 /* CLDNTaskDelegate.swift */; };\n\t\tOBJ_268 /* CLDNTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_21 /* CLDNTimeline.swift */; };\n\t\tOBJ_269 /* CLDNValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_22 /* CLDNValidation.swift */; };\n\t\tOBJ_270 /* DispatchQueue+Cloudinary.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_23 /* DispatchQueue+Cloudinary.swift */; };\n\t\tOBJ_271 /* CLDCloudinary.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_24 /* CLDCloudinary.swift */; };\n\t\tOBJ_272 /* CLDCompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_25 /* CLDCompatibility.swift */; };\n\t\tOBJ_273 /* CLDConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_26 /* CLDConfiguration.swift */; };\n\t\tOBJ_274 /* CLDEagerTransformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_27 /* CLDEagerTransformation.swift */; };\n\t\tOBJ_275 /* CLDResponsiveParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_28 /* CLDResponsiveParams.swift */; };\n\t\tOBJ_304 /* CLDDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_73 /* CLDDownloader.swift */; };\n\t\tOBJ_305 /* CLDBaseNetworkObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_75 /* CLDBaseNetworkObject.swift */; };\n\t\tOBJ_306 /* CLDConditionExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_76 /* CLDConditionExpression.swift */; };\n\t\tOBJ_307 /* CLDDefinitions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_77 /* CLDDefinitions.swift */; };\n\t\tOBJ_308 /* CLDExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_78 /* CLDExpression.swift */; };\n\t\tOBJ_309 /* CLDOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_79 /* CLDOperators.swift */; };\n\t\tOBJ_310 /* CLDTransformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_80 /* CLDTransformation.swift */; };\n\t\tOBJ_311 /* CLDVariable.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_81 /* CLDVariable.swift */; };\n\t\tOBJ_312 /* CLDFetchLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_83 /* CLDFetchLayer.swift */; };\n\t\tOBJ_313 /* CLDLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_84 /* CLDLayer.swift */; };\n\t\tOBJ_314 /* CLDSubtitlesLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_85 /* CLDSubtitlesLayer.swift */; };\n\t\tOBJ_315 /* CLDTextLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_86 /* CLDTextLayer.swift */; };\n\t\tOBJ_316 /* CLDRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_88 /* CLDRequestParams.swift */; };\n\t\tOBJ_317 /* CLDRequestParamsHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_90 /* CLDRequestParamsHelpers.swift */; };\n\t\tOBJ_318 /* CLDRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_92 /* CLDRequest.swift */; };\n\t\tOBJ_319 /* CLDBaseResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_94 /* CLDBaseResult.swift */; };\n\t\tOBJ_320 /* CLDAccessibilityAnalysisResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_97 /* CLDAccessibilityAnalysisResult.swift */; };\n\t\tOBJ_321 /* CLDColorblindAccessibilityAnalysisResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_98 /* CLDColorblindAccessibilityAnalysisResult.swift */; };\n\t\tOBJ_322 /* CLDBoundingBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_99 /* CLDBoundingBox.swift */; };\n\t\tOBJ_323 /* CLDDetection.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_100 /* CLDDetection.swift */; };\n\t\tOBJ_324 /* CLDFace.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_101 /* CLDFace.swift */; };\n\t\tOBJ_325 /* CLDInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_102 /* CLDInfo.swift */; };\n\t\tOBJ_326 /* CLDAdvOcrResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_104 /* CLDAdvOcrResult.swift */; };\n\t\tOBJ_327 /* CLDOcrBlockResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_105 /* CLDOcrBlockResult.swift */; };\n\t\tOBJ_328 /* CLDOcrBoundindBlockResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_106 /* CLDOcrBoundindBlockResult.swift */; };\n\t\tOBJ_329 /* CLDOcrDataResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_107 /* CLDOcrDataResult.swift */; };\n\t\tOBJ_330 /* CLDOcrDetectedLanguagesResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_108 /* CLDOcrDetectedLanguagesResult.swift */; };\n\t\tOBJ_331 /* CLDOcrFullTextAnnotationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_109 /* CLDOcrFullTextAnnotationResult.swift */; };\n\t\tOBJ_332 /* CLDOcrPageResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_110 /* CLDOcrPageResult.swift */; };\n\t\tOBJ_333 /* CLDOcrParagraphResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_111 /* CLDOcrParagraphResult.swift */; };\n\t\tOBJ_334 /* CLDOcrPropertyResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_112 /* CLDOcrPropertyResult.swift */; };\n\t\tOBJ_335 /* CLDOcrResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_113 /* CLDOcrResult.swift */; };\n\t\tOBJ_336 /* CLDOcrSymbolResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_114 /* CLDOcrSymbolResult.swift */; };\n\t\tOBJ_337 /* CLDOcrTextAnnotationResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_115 /* CLDOcrTextAnnotationResult.swift */; };\n\t\tOBJ_338 /* CLDOcrWordResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_116 /* CLDOcrWordResult.swift */; };\n\t\tOBJ_339 /* CLDQualityAnalysis.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_118 /* CLDQualityAnalysis.swift */; };\n\t\tOBJ_340 /* CLDRekognitionFace.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_119 /* CLDRekognitionFace.swift */; };\n\t\tOBJ_341 /* CommonResultKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_120 /* CommonResultKeys.swift */; };\n\t\tOBJ_342 /* CLDManagementApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_122 /* CLDManagementApi.swift */; };\n\t\tOBJ_343 /* CLDDeleteRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_124 /* CLDDeleteRequest.swift */; };\n\t\tOBJ_344 /* CLDExplicitRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_125 /* CLDExplicitRequest.swift */; };\n\t\tOBJ_345 /* CLDExplodeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_126 /* CLDExplodeRequest.swift */; };\n\t\tOBJ_346 /* CLDMultiRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_127 /* CLDMultiRequest.swift */; };\n\t\tOBJ_347 /* CLDRenameRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_128 /* CLDRenameRequest.swift */; };\n\t\tOBJ_348 /* CLDSpriteRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_129 /* CLDSpriteRequest.swift */; };\n\t\tOBJ_349 /* CLDTagRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_130 /* CLDTagRequest.swift */; };\n\t\tOBJ_350 /* CLDTextRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_131 /* CLDTextRequest.swift */; };\n\t\tOBJ_351 /* CLDDeleteByTokenRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_133 /* CLDDeleteByTokenRequestParams.swift */; };\n\t\tOBJ_352 /* CLDDestroyRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_134 /* CLDDestroyRequestParams.swift */; };\n\t\tOBJ_353 /* CLDExplicitRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_135 /* CLDExplicitRequestParams.swift */; };\n\t\tOBJ_354 /* CLDExplodeRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_136 /* CLDExplodeRequestParams.swift */; };\n\t\tOBJ_355 /* CLDMultiRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_137 /* CLDMultiRequestParams.swift */; };\n\t\tOBJ_356 /* CLDRenameRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_138 /* CLDRenameRequestParams.swift */; };\n\t\tOBJ_357 /* CLDSpriteRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_139 /* CLDSpriteRequestParams.swift */; };\n\t\tOBJ_358 /* CLDTagsRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_140 /* CLDTagsRequestParams.swift */; };\n\t\tOBJ_359 /* CLDTextRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_141 /* CLDTextRequestParams.swift */; };\n\t\tOBJ_360 /* CLDDeleteResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_143 /* CLDDeleteResult.swift */; };\n\t\tOBJ_361 /* CLDExplicitResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_144 /* CLDExplicitResult.swift */; };\n\t\tOBJ_362 /* CLDExplodeResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_145 /* CLDExplodeResult.swift */; };\n\t\tOBJ_363 /* CLDMultiResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_146 /* CLDMultiResult.swift */; };\n\t\tOBJ_364 /* CLDRenameResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_147 /* CLDRenameResult.swift */; };\n\t\tOBJ_365 /* CLDSpriteResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_148 /* CLDSpriteResult.swift */; };\n\t\tOBJ_366 /* CLDTagResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_149 /* CLDTagResult.swift */; };\n\t\tOBJ_367 /* CLDTextResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_150 /* CLDTextResult.swift */; };\n\t\tOBJ_368 /* CLDUploaderWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_152 /* CLDUploaderWidget.swift */; };\n\t\tOBJ_369 /* CLDCropOverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_154 /* CLDCropOverlayView.swift */; };\n\t\tOBJ_370 /* CLDCropScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_155 /* CLDCropScrollView.swift */; };\n\t\tOBJ_371 /* CLDCropScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_156 /* CLDCropScrollViewController.swift */; };\n\t\tOBJ_372 /* CLDCropView.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_157 /* CLDCropView.swift */; };\n\t\tOBJ_373 /* CLDCropViewCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_158 /* CLDCropViewCalculator.swift */; };\n\t\tOBJ_374 /* CLDCropViewUIManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_159 /* CLDCropViewUIManager.swift */; };\n\t\tOBJ_375 /* CLDWidgetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_161 /* CLDWidgetConfiguration.swift */; };\n\t\tOBJ_376 /* CLDWidgetAssetContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_163 /* CLDWidgetAssetContainer.swift */; };\n\t\tOBJ_377 /* CLDWidgetPreviewCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_164 /* CLDWidgetPreviewCollectionCell.swift */; };\n\t\tOBJ_378 /* BackIconInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_166 /* BackIconInstructions.swift */; };\n\t\tOBJ_379 /* CropIconInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_167 /* CropIconInstructions.swift */; };\n\t\tOBJ_380 /* CropRotateIconInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_168 /* CropRotateIconInstructions.swift */; };\n\t\tOBJ_381 /* DoneIconInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_169 /* DoneIconInstructions.swift */; };\n\t\tOBJ_382 /* RatioLockedIconInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_170 /* RatioLockedIconInstructions.swift */; };\n\t\tOBJ_383 /* RatioOpenedIconInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_171 /* RatioOpenedIconInstructions.swift */; };\n\t\tOBJ_384 /* RotateIconInstructions.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_172 /* RotateIconInstructions.swift */; };\n\t\tOBJ_385 /* CLDDisplayLinkObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_174 /* CLDDisplayLinkObserver.swift */; };\n\t\tOBJ_386 /* CLDVideoControlsState.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_175 /* CLDVideoControlsState.swift */; };\n\t\tOBJ_387 /* CLDVideoControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_176 /* CLDVideoControlsView.swift */; };\n\t\tOBJ_388 /* CLDVideoHiddenAndPausedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_177 /* CLDVideoHiddenAndPausedState.swift */; };\n\t\tOBJ_389 /* CLDVideoHiddenAndPlayingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_178 /* CLDVideoHiddenAndPlayingState.swift */; };\n\t\tOBJ_390 /* CLDVideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_179 /* CLDVideoPlayerView.swift */; };\n\t\tOBJ_391 /* CLDVideoShownAndPausedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_180 /* CLDVideoShownAndPausedState.swift */; };\n\t\tOBJ_392 /* CLDVideoShownAndPlayingState.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_181 /* CLDVideoShownAndPlayingState.swift */; };\n\t\tOBJ_393 /* CLDVideoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_182 /* CLDVideoView.swift */; };\n\t\tOBJ_394 /* CLDWidgetEditViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_184 /* CLDWidgetEditViewController.swift */; };\n\t\tOBJ_395 /* CLDWidgetPreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_185 /* CLDWidgetPreviewViewController.swift */; };\n\t\tOBJ_396 /* CLDWidgetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_186 /* CLDWidgetViewController.swift */; };\n\t\tOBJ_397 /* CLDUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_188 /* CLDUploader.swift */; };\n\t\tOBJ_398 /* CLDPreprocessChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_190 /* CLDPreprocessChain.swift */; };\n\t\tOBJ_399 /* CLDUploadRequestParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_192 /* CLDUploadRequestParams.swift */; };\n\t\tOBJ_400 /* CLDDefaultUploadRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_194 /* CLDDefaultUploadRequest.swift */; };\n\t\tOBJ_401 /* CLDUploadRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_195 /* CLDUploadRequest.swift */; };\n\t\tOBJ_402 /* CLDUploadRequestWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_196 /* CLDUploadRequestWrapper.swift */; };\n\t\tOBJ_403 /* CLDUploadResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_198 /* CLDUploadResult.swift */; };\n\t\tOBJ_404 /* CLDUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_200 /* CLDUrl.swift */; };\n\t\tOBJ_405 /* CLDNetworkAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_203 /* CLDNetworkAdapter.swift */; };\n\t\tOBJ_406 /* CLDDefaultNetworkAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_204 /* CLDDefaultNetworkAdapter.swift */; };\n\t\tOBJ_407 /* CLDNetworkCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_205 /* CLDNetworkCoordinator.swift */; };\n\t\tOBJ_408 /* CLDAsyncNetworkUploadRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_207 /* CLDAsyncNetworkUploadRequest.swift */; };\n\t\tOBJ_409 /* CLDErrorRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_208 /* CLDErrorRequest.swift */; };\n\t\tOBJ_410 /* CLDGenericNetworkRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_209 /* CLDGenericNetworkRequest.swift */; };\n\t\tOBJ_411 /* CLDNetworkDataRequestImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_210 /* CLDNetworkDataRequestImpl.swift */; };\n\t\tOBJ_412 /* CLDNetworkDownloadRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_211 /* CLDNetworkDownloadRequest.swift */; };\n\t\tOBJ_413 /* CLDNetworkUploadRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_212 /* CLDNetworkUploadRequest.swift */; };\n\t\tOBJ_414 /* CLDBuildParamsUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_214 /* CLDBuildParamsUtils.swift */; };\n\t\tOBJ_415 /* CLDCryptoUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_215 /* CLDCryptoUtils.swift */; };\n\t\tOBJ_416 /* CLDDictionaryUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_216 /* CLDDictionaryUtils.swift */; };\n\t\tOBJ_417 /* CLDError.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_217 /* CLDError.swift */; };\n\t\tOBJ_418 /* CLDFileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_218 /* CLDFileUtils.swift */; };\n\t\tOBJ_420 /* CLDImageGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_221 /* CLDImageGenerator.swift */; };\n\t\tOBJ_421 /* CLDImageUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_222 /* CLDImageUtils.swift */; };\n\t\tOBJ_422 /* CLDJsonUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_223 /* CLDJsonUtils.swift */; };\n\t\tOBJ_423 /* CLDLogManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_224 /* CLDLogManager.swift */; };\n\t\tOBJ_424 /* CLDStringUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_225 /* CLDStringUtils.swift */; };\n\t\tOBJ_425 /* CLDTransformation+Ios.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_228 /* CLDTransformation+Ios.swift */; };\n\t\tOBJ_426 /* ExtensionCLDDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_229 /* ExtensionCLDDownloader.swift */; };\n\t\tOBJ_427 /* UIButton+Cloudinary.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_230 /* UIButton+Cloudinary.swift */; };\n\t\tOBJ_428 /* UIImageView+Cloudinary.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_231 /* UIImageView+Cloudinary.swift */; };\n\t\tOBJ_429 /* UIView+Cloudinary.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_232 /* UIView+Cloudinary.swift */; };\n\t\tOBJ_430 /* CLDFetchAssetRequestImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_234 /* CLDFetchAssetRequestImpl.swift */; };\n\t\tOBJ_431 /* CLDFetchImageRequestImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_235 /* CLDFetchImageRequestImpl.swift */; };\n\t\tOBJ_432 /* CLDResponsiveViewHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_237 /* CLDResponsiveViewHelper.swift */; };\n\t\tOBJ_433 /* CLDUIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_238 /* CLDUIImageView.swift */; };\n\t\tOBJ_434 /* CLDImagePreprocessChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_240 /* CLDImagePreprocessChain.swift */; };\n\t\tOBJ_435 /* CLDPreprocessHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_241 /* CLDPreprocessHelpers.swift */; };\n\t\tOBJ_442 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXFileReference section */\n\t\tB690BF5D2BC55992007117AC /* HTTPStatusCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = HTTPStatusCode.swift; path = CacheSystem/Enum/HTTPStatusCode.swift; sourceTree = \"<group>\"; };\n\t\tB694AAEB2B308AF100075041 /* CLDAnalytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLDAnalytics.swift; sourceTree = \"<group>\"; };\n\t\tB694AAEE2B308B8400075041 /* VideoAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoAnalytics.swift; sourceTree = \"<group>\"; };\n\t\tB694AAF02B308B9D00075041 /* VideoEventsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoEventsManager.swift; sourceTree = \"<group>\"; };\n\t\tB6B4C4992C560FEE00C9B604 /* CLDVideoPreprocessChain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoPreprocessChain.swift; sourceTree = \"<group>\"; };\n\t\tB6B4C49B2C56100600C9B604 /* CLDVideoTranscode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoTranscode.swift; sourceTree = \"<group>\"; };\n\t\tB6B4C4A02C5615CF00C9B604 /* CLDVideoPreprocessHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoPreprocessHelpers.swift; sourceTree = \"<group>\"; };\n\t\tB6C2D4852A724C4200AA0039 /* CLDVideoPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoPlayer.swift; sourceTree = \"<group>\"; };\n\t\t\"Cloudinary::Cloudinary::Product\" /* Cloudinary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Cloudinary.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tOBJ_10 /* CLDNConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNConvertible.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_100 /* CLDDetection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDetection.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_101 /* CLDFace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDFace.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_102 /* CLDInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDInfo.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_104 /* CLDAdvOcrResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDAdvOcrResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_105 /* CLDOcrBlockResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrBlockResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_106 /* CLDOcrBoundindBlockResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrBoundindBlockResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_107 /* CLDOcrDataResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrDataResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_108 /* CLDOcrDetectedLanguagesResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrDetectedLanguagesResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_109 /* CLDOcrFullTextAnnotationResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrFullTextAnnotationResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_11 /* CLDNError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNError.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_110 /* CLDOcrPageResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrPageResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_111 /* CLDOcrParagraphResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrParagraphResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_112 /* CLDOcrPropertyResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrPropertyResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_113 /* CLDOcrResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_114 /* CLDOcrSymbolResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrSymbolResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_115 /* CLDOcrTextAnnotationResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrTextAnnotationResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_116 /* CLDOcrWordResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOcrWordResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_118 /* CLDQualityAnalysis.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDQualityAnalysis.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_119 /* CLDRekognitionFace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDRekognitionFace.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_12 /* CLDNMultipartFormData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNMultipartFormData.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_120 /* CommonResultKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonResultKeys.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_122 /* CLDManagementApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDManagementApi.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_124 /* CLDDeleteRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDeleteRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_125 /* CLDExplicitRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDExplicitRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_126 /* CLDExplodeRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDExplodeRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_127 /* CLDMultiRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDMultiRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_128 /* CLDRenameRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDRenameRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_129 /* CLDSpriteRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDSpriteRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_13 /* CLDNParameterEncoding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNParameterEncoding.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_130 /* CLDTagRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTagRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_131 /* CLDTextRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTextRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_133 /* CLDDeleteByTokenRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDeleteByTokenRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_134 /* CLDDestroyRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDestroyRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_135 /* CLDExplicitRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDExplicitRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_136 /* CLDExplodeRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDExplodeRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_137 /* CLDMultiRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDMultiRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_138 /* CLDRenameRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDRenameRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_139 /* CLDSpriteRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDSpriteRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_14 /* CLDNRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_140 /* CLDTagsRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTagsRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_141 /* CLDTextRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTextRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_143 /* CLDDeleteResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDeleteResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_144 /* CLDExplicitResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDExplicitResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_145 /* CLDExplodeResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDExplodeResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_146 /* CLDMultiResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDMultiResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_147 /* CLDRenameResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDRenameResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_148 /* CLDSpriteResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDSpriteResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_149 /* CLDTagResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTagResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_15 /* CLDNResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNResponse.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_150 /* CLDTextResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTextResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_152 /* CLDUploaderWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDUploaderWidget.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_154 /* CLDCropOverlayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDCropOverlayView.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_155 /* CLDCropScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDCropScrollView.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_156 /* CLDCropScrollViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDCropScrollViewController.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_157 /* CLDCropView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDCropView.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_158 /* CLDCropViewCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDCropViewCalculator.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_159 /* CLDCropViewUIManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDCropViewUIManager.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_16 /* CLDNResponseSerialization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNResponseSerialization.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_161 /* CLDWidgetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDWidgetConfiguration.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_163 /* CLDWidgetAssetContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDWidgetAssetContainer.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_164 /* CLDWidgetPreviewCollectionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDWidgetPreviewCollectionCell.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_166 /* BackIconInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackIconInstructions.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_167 /* CropIconInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CropIconInstructions.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_168 /* CropRotateIconInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CropRotateIconInstructions.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_169 /* DoneIconInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoneIconInstructions.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_17 /* CLDNResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_170 /* RatioLockedIconInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatioLockedIconInstructions.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_171 /* RatioOpenedIconInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatioOpenedIconInstructions.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_172 /* RotateIconInstructions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RotateIconInstructions.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_174 /* CLDDisplayLinkObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDisplayLinkObserver.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_175 /* CLDVideoControlsState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoControlsState.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_176 /* CLDVideoControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoControlsView.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_177 /* CLDVideoHiddenAndPausedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoHiddenAndPausedState.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_178 /* CLDVideoHiddenAndPlayingState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoHiddenAndPlayingState.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_179 /* CLDVideoPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoPlayerView.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_18 /* CLDNSessionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNSessionDelegate.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_180 /* CLDVideoShownAndPausedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoShownAndPausedState.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_181 /* CLDVideoShownAndPlayingState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoShownAndPlayingState.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_182 /* CLDVideoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoView.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_184 /* CLDWidgetEditViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDWidgetEditViewController.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_185 /* CLDWidgetPreviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDWidgetPreviewViewController.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_186 /* CLDWidgetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDWidgetViewController.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_188 /* CLDUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDUploader.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_19 /* CLDNSessionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNSessionManager.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_190 /* CLDPreprocessChain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDPreprocessChain.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_192 /* CLDUploadRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDUploadRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_194 /* CLDDefaultUploadRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDefaultUploadRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_195 /* CLDUploadRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDUploadRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_196 /* CLDUploadRequestWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDUploadRequestWrapper.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_198 /* CLDUploadResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDUploadResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_20 /* CLDNTaskDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNTaskDelegate.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_200 /* CLDUrl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDUrl.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_203 /* CLDNetworkAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNetworkAdapter.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_204 /* CLDDefaultNetworkAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDefaultNetworkAdapter.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_205 /* CLDNetworkCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNetworkCoordinator.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_207 /* CLDAsyncNetworkUploadRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDAsyncNetworkUploadRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_208 /* CLDErrorRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDErrorRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_209 /* CLDGenericNetworkRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDGenericNetworkRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_21 /* CLDNTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNTimeline.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_210 /* CLDNetworkDataRequestImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNetworkDataRequestImpl.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_211 /* CLDNetworkDownloadRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNetworkDownloadRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_212 /* CLDNetworkUploadRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNetworkUploadRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_214 /* CLDBuildParamsUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDBuildParamsUtils.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_215 /* CLDCryptoUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDCryptoUtils.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_216 /* CLDDictionaryUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDictionaryUtils.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_217 /* CLDError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDError.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_218 /* CLDFileUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDFileUtils.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_22 /* CLDNValidation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDNValidation.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_221 /* CLDImageGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDImageGenerator.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_222 /* CLDImageUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDImageUtils.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_223 /* CLDJsonUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDJsonUtils.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_224 /* CLDLogManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDLogManager.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_225 /* CLDStringUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDStringUtils.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_228 /* CLDTransformation+Ios.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"CLDTransformation+Ios.swift\"; sourceTree = \"<group>\"; };\n\t\tOBJ_229 /* ExtensionCLDDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionCLDDownloader.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_23 /* DispatchQueue+Cloudinary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"DispatchQueue+Cloudinary.swift\"; sourceTree = \"<group>\"; };\n\t\tOBJ_230 /* UIButton+Cloudinary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"UIButton+Cloudinary.swift\"; sourceTree = \"<group>\"; };\n\t\tOBJ_231 /* UIImageView+Cloudinary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"UIImageView+Cloudinary.swift\"; sourceTree = \"<group>\"; };\n\t\tOBJ_232 /* UIView+Cloudinary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"UIView+Cloudinary.swift\"; sourceTree = \"<group>\"; };\n\t\tOBJ_234 /* CLDFetchAssetRequestImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDFetchAssetRequestImpl.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_235 /* CLDFetchImageRequestImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDFetchImageRequestImpl.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_237 /* CLDResponsiveViewHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDResponsiveViewHelper.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_238 /* CLDUIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDUIImageView.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_24 /* CLDCloudinary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDCloudinary.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_240 /* CLDImagePreprocessChain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDImagePreprocessChain.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_241 /* CLDPreprocessHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDPreprocessHelpers.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_245 /* tools */ = {isa = PBXFileReference; lastKnownFileType = folder; path = tools; sourceTree = SOURCE_ROOT; };\n\t\tOBJ_246 /* Example */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Example; sourceTree = SOURCE_ROOT; };\n\t\tOBJ_247 /* Cloudinary */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Cloudinary; sourceTree = SOURCE_ROOT; };\n\t\tOBJ_248 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = \"<group>\"; };\n\t\tOBJ_249 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = \"<group>\"; };\n\t\tOBJ_25 /* CLDCompatibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDCompatibility.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_250 /* Cloudinary.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cloudinary.podspec; sourceTree = \"<group>\"; };\n\t\tOBJ_251 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = \"<group>\"; };\n\t\tOBJ_26 /* CLDConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDConfiguration.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_27 /* CLDEagerTransformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDEagerTransformation.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_28 /* CLDResponsiveParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDResponsiveParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_73 /* CLDDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDownloader.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_75 /* CLDBaseNetworkObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDBaseNetworkObject.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_76 /* CLDConditionExpression.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDConditionExpression.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_77 /* CLDDefinitions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDDefinitions.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_78 /* CLDExpression.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDExpression.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_79 /* CLDOperators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDOperators.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_80 /* CLDTransformation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTransformation.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_81 /* CLDVariable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVariable.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_83 /* CLDFetchLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDFetchLayer.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_84 /* CLDLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDLayer.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_85 /* CLDSubtitlesLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDSubtitlesLayer.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_86 /* CLDTextLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTextLayer.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_88 /* CLDRequestParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDRequestParams.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_90 /* CLDRequestParamsHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDRequestParamsHelpers.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_92 /* CLDRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDRequest.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_94 /* CLDBaseResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDBaseResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_97 /* CLDAccessibilityAnalysisResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDAccessibilityAnalysisResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_98 /* CLDColorblindAccessibilityAnalysisResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDColorblindAccessibilityAnalysisResult.swift; sourceTree = \"<group>\"; };\n\t\tOBJ_99 /* CLDBoundingBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDBoundingBox.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tOBJ_436 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 0;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tB694AAED2B308B7600075041 /* Analytics */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB694AAEE2B308B8400075041 /* VideoAnalytics.swift */,\n\t\t\t\tB694AAF02B308B9D00075041 /* VideoEventsManager.swift */,\n\t\t\t);\n\t\t\tpath = Analytics;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB6C2D4842A724C2F00AA0039 /* Video */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB694AAED2B308B7600075041 /* Analytics */,\n\t\t\t\tB6C2D4852A724C4200AA0039 /* CLDVideoPlayer.swift */,\n\t\t\t);\n\t\t\tpath = Video;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_103 /* CLDOcr */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_104 /* CLDAdvOcrResult.swift */,\n\t\t\t\tOBJ_105 /* CLDOcrBlockResult.swift */,\n\t\t\t\tOBJ_106 /* CLDOcrBoundindBlockResult.swift */,\n\t\t\t\tOBJ_107 /* CLDOcrDataResult.swift */,\n\t\t\t\tOBJ_108 /* CLDOcrDetectedLanguagesResult.swift */,\n\t\t\t\tOBJ_109 /* CLDOcrFullTextAnnotationResult.swift */,\n\t\t\t\tOBJ_110 /* CLDOcrPageResult.swift */,\n\t\t\t\tOBJ_111 /* CLDOcrParagraphResult.swift */,\n\t\t\t\tOBJ_112 /* CLDOcrPropertyResult.swift */,\n\t\t\t\tOBJ_113 /* CLDOcrResult.swift */,\n\t\t\t\tOBJ_114 /* CLDOcrSymbolResult.swift */,\n\t\t\t\tOBJ_115 /* CLDOcrTextAnnotationResult.swift */,\n\t\t\t\tOBJ_116 /* CLDOcrWordResult.swift */,\n\t\t\t);\n\t\t\tpath = CLDOcr;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_117 /* CLDQualityAnalysis */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_118 /* CLDQualityAnalysis.swift */,\n\t\t\t);\n\t\t\tpath = CLDQualityAnalysis;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_121 /* ManagementApi */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_122 /* CLDManagementApi.swift */,\n\t\t\t\tOBJ_123 /* Requests */,\n\t\t\t\tOBJ_132 /* RequestsParams */,\n\t\t\t\tOBJ_142 /* Results */,\n\t\t\t);\n\t\t\tpath = ManagementApi;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_123 /* Requests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_124 /* CLDDeleteRequest.swift */,\n\t\t\t\tOBJ_125 /* CLDExplicitRequest.swift */,\n\t\t\t\tOBJ_126 /* CLDExplodeRequest.swift */,\n\t\t\t\tOBJ_127 /* CLDMultiRequest.swift */,\n\t\t\t\tOBJ_128 /* CLDRenameRequest.swift */,\n\t\t\t\tOBJ_129 /* CLDSpriteRequest.swift */,\n\t\t\t\tOBJ_130 /* CLDTagRequest.swift */,\n\t\t\t\tOBJ_131 /* CLDTextRequest.swift */,\n\t\t\t);\n\t\t\tpath = Requests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_132 /* RequestsParams */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_133 /* CLDDeleteByTokenRequestParams.swift */,\n\t\t\t\tOBJ_134 /* CLDDestroyRequestParams.swift */,\n\t\t\t\tOBJ_135 /* CLDExplicitRequestParams.swift */,\n\t\t\t\tOBJ_136 /* CLDExplodeRequestParams.swift */,\n\t\t\t\tOBJ_137 /* CLDMultiRequestParams.swift */,\n\t\t\t\tOBJ_138 /* CLDRenameRequestParams.swift */,\n\t\t\t\tOBJ_139 /* CLDSpriteRequestParams.swift */,\n\t\t\t\tOBJ_140 /* CLDTagsRequestParams.swift */,\n\t\t\t\tOBJ_141 /* CLDTextRequestParams.swift */,\n\t\t\t);\n\t\t\tpath = RequestsParams;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_142 /* Results */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_143 /* CLDDeleteResult.swift */,\n\t\t\t\tOBJ_144 /* CLDExplicitResult.swift */,\n\t\t\t\tOBJ_145 /* CLDExplodeResult.swift */,\n\t\t\t\tOBJ_146 /* CLDMultiResult.swift */,\n\t\t\t\tOBJ_147 /* CLDRenameResult.swift */,\n\t\t\t\tOBJ_148 /* CLDSpriteResult.swift */,\n\t\t\t\tOBJ_149 /* CLDTagResult.swift */,\n\t\t\t\tOBJ_150 /* CLDTextResult.swift */,\n\t\t\t);\n\t\t\tpath = Results;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_151 /* UploadWidget */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_152 /* CLDUploaderWidget.swift */,\n\t\t\t\tOBJ_153 /* CropView */,\n\t\t\t\tOBJ_160 /* WidgetConfiguration */,\n\t\t\t\tOBJ_162 /* WidgetElements */,\n\t\t\t\tOBJ_165 /* WidgetImages */,\n\t\t\t\tOBJ_173 /* WidgetVideo */,\n\t\t\t\tOBJ_183 /* WidgetViewControllers */,\n\t\t\t);\n\t\t\tpath = UploadWidget;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_153 /* CropView */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_154 /* CLDCropOverlayView.swift */,\n\t\t\t\tOBJ_155 /* CLDCropScrollView.swift */,\n\t\t\t\tOBJ_156 /* CLDCropScrollViewController.swift */,\n\t\t\t\tOBJ_157 /* CLDCropView.swift */,\n\t\t\t\tOBJ_158 /* CLDCropViewCalculator.swift */,\n\t\t\t\tOBJ_159 /* CLDCropViewUIManager.swift */,\n\t\t\t);\n\t\t\tpath = CropView;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_160 /* WidgetConfiguration */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_161 /* CLDWidgetConfiguration.swift */,\n\t\t\t);\n\t\t\tpath = WidgetConfiguration;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_162 /* WidgetElements */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_163 /* CLDWidgetAssetContainer.swift */,\n\t\t\t\tOBJ_164 /* CLDWidgetPreviewCollectionCell.swift */,\n\t\t\t);\n\t\t\tpath = WidgetElements;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_165 /* WidgetImages */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_166 /* BackIconInstructions.swift */,\n\t\t\t\tOBJ_167 /* CropIconInstructions.swift */,\n\t\t\t\tOBJ_168 /* CropRotateIconInstructions.swift */,\n\t\t\t\tOBJ_169 /* DoneIconInstructions.swift */,\n\t\t\t\tOBJ_170 /* RatioLockedIconInstructions.swift */,\n\t\t\t\tOBJ_171 /* RatioOpenedIconInstructions.swift */,\n\t\t\t\tOBJ_172 /* RotateIconInstructions.swift */,\n\t\t\t);\n\t\t\tpath = WidgetImages;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_173 /* WidgetVideo */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_174 /* CLDDisplayLinkObserver.swift */,\n\t\t\t\tOBJ_175 /* CLDVideoControlsState.swift */,\n\t\t\t\tOBJ_176 /* CLDVideoControlsView.swift */,\n\t\t\t\tOBJ_177 /* CLDVideoHiddenAndPausedState.swift */,\n\t\t\t\tOBJ_178 /* CLDVideoHiddenAndPlayingState.swift */,\n\t\t\t\tOBJ_179 /* CLDVideoPlayerView.swift */,\n\t\t\t\tOBJ_180 /* CLDVideoShownAndPausedState.swift */,\n\t\t\t\tOBJ_181 /* CLDVideoShownAndPlayingState.swift */,\n\t\t\t\tOBJ_182 /* CLDVideoView.swift */,\n\t\t\t);\n\t\t\tpath = WidgetVideo;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_183 /* WidgetViewControllers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_184 /* CLDWidgetEditViewController.swift */,\n\t\t\t\tOBJ_185 /* CLDWidgetPreviewViewController.swift */,\n\t\t\t\tOBJ_186 /* CLDWidgetViewController.swift */,\n\t\t\t);\n\t\t\tpath = WidgetViewControllers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_187 /* Uploader */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_188 /* CLDUploader.swift */,\n\t\t\t\tOBJ_189 /* Preupload */,\n\t\t\t\tOBJ_191 /* RequestParams */,\n\t\t\t\tOBJ_193 /* Requests */,\n\t\t\t\tOBJ_197 /* Results */,\n\t\t\t);\n\t\t\tpath = Uploader;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_189 /* Preupload */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_190 /* CLDPreprocessChain.swift */,\n\t\t\t);\n\t\t\tpath = Preupload;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_191 /* RequestParams */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_192 /* CLDUploadRequestParams.swift */,\n\t\t\t);\n\t\t\tpath = RequestParams;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_193 /* Requests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_194 /* CLDDefaultUploadRequest.swift */,\n\t\t\t\tOBJ_195 /* CLDUploadRequest.swift */,\n\t\t\t\tOBJ_196 /* CLDUploadRequestWrapper.swift */,\n\t\t\t);\n\t\t\tpath = Requests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_197 /* Results */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_198 /* CLDUploadResult.swift */,\n\t\t\t);\n\t\t\tpath = Results;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_199 /* Url */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_200 /* CLDUrl.swift */,\n\t\t\t);\n\t\t\tpath = Url;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_201 /* Network */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_202 /* Adapter */,\n\t\t\t\tOBJ_204 /* CLDDefaultNetworkAdapter.swift */,\n\t\t\t\tOBJ_205 /* CLDNetworkCoordinator.swift */,\n\t\t\t\tOBJ_206 /* NetworkRequest */,\n\t\t\t);\n\t\t\tpath = Network;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_202 /* Adapter */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_203 /* CLDNetworkAdapter.swift */,\n\t\t\t);\n\t\t\tpath = Adapter;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_206 /* NetworkRequest */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_207 /* CLDAsyncNetworkUploadRequest.swift */,\n\t\t\t\tOBJ_208 /* CLDErrorRequest.swift */,\n\t\t\t\tOBJ_209 /* CLDGenericNetworkRequest.swift */,\n\t\t\t\tOBJ_210 /* CLDNetworkDataRequestImpl.swift */,\n\t\t\t\tOBJ_211 /* CLDNetworkDownloadRequest.swift */,\n\t\t\t\tOBJ_212 /* CLDNetworkUploadRequest.swift */,\n\t\t\t);\n\t\t\tpath = NetworkRequest;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_213 /* Utils */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_214 /* CLDBuildParamsUtils.swift */,\n\t\t\t\tOBJ_215 /* CLDCryptoUtils.swift */,\n\t\t\t\tOBJ_216 /* CLDDictionaryUtils.swift */,\n\t\t\t\tOBJ_217 /* CLDError.swift */,\n\t\t\t\tOBJ_218 /* CLDFileUtils.swift */,\n\t\t\t\tOBJ_220 /* CLDImageGenerator */,\n\t\t\t\tOBJ_222 /* CLDImageUtils.swift */,\n\t\t\t\tOBJ_223 /* CLDJsonUtils.swift */,\n\t\t\t\tOBJ_224 /* CLDLogManager.swift */,\n\t\t\t\tOBJ_225 /* CLDStringUtils.swift */,\n\t\t\t);\n\t\t\tpath = Utils;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_220 /* CLDImageGenerator */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_221 /* CLDImageGenerator.swift */,\n\t\t\t);\n\t\t\tpath = CLDImageGenerator;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_226 /* ios */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB6C2D4842A724C2F00AA0039 /* Video */,\n\t\t\t\tOBJ_227 /* Extensions */,\n\t\t\t\tOBJ_233 /* NetworkRequest */,\n\t\t\t\tOBJ_236 /* UIViews */,\n\t\t\t\tOBJ_239 /* Uploader */,\n\t\t\t);\n\t\t\tpath = ios;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_227 /* Extensions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_228 /* CLDTransformation+Ios.swift */,\n\t\t\t\tOBJ_229 /* ExtensionCLDDownloader.swift */,\n\t\t\t\tOBJ_230 /* UIButton+Cloudinary.swift */,\n\t\t\t\tOBJ_231 /* UIImageView+Cloudinary.swift */,\n\t\t\t\tOBJ_232 /* UIView+Cloudinary.swift */,\n\t\t\t);\n\t\t\tpath = Extensions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_233 /* NetworkRequest */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_234 /* CLDFetchAssetRequestImpl.swift */,\n\t\t\t\tOBJ_235 /* CLDFetchImageRequestImpl.swift */,\n\t\t\t);\n\t\t\tpath = NetworkRequest;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_236 /* UIViews */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_237 /* CLDResponsiveViewHelper.swift */,\n\t\t\t\tOBJ_238 /* CLDUIImageView.swift */,\n\t\t\t);\n\t\t\tpath = UIViews;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_239 /* Uploader */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_240 /* CLDImagePreprocessChain.swift */,\n\t\t\t\tOBJ_241 /* CLDPreprocessHelpers.swift */,\n\t\t\t\tB6B4C4992C560FEE00C9B604 /* CLDVideoPreprocessChain.swift */,\n\t\t\t\tB6B4C49B2C56100600C9B604 /* CLDVideoTranscode.swift */,\n\t\t\t\tB6B4C4A02C5615CF00C9B604 /* CLDVideoPreprocessHelpers.swift */,\n\t\t\t);\n\t\t\tpath = Uploader;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_242 /* Tests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tname = Tests;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\tOBJ_243 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t\"Cloudinary::Cloudinary::Product\" /* Cloudinary.framework */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = BUILT_PRODUCTS_DIR;\n\t\t};\n\t\tOBJ_29 /* Features */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB690BF5D2BC55992007117AC /* HTTPStatusCode.swift */,\n\t\t\t\tOBJ_72 /* Downloader */,\n\t\t\t\tOBJ_74 /* Helpers */,\n\t\t\t\tOBJ_121 /* ManagementApi */,\n\t\t\t\tOBJ_151 /* UploadWidget */,\n\t\t\t\tOBJ_187 /* Uploader */,\n\t\t\t\tOBJ_199 /* Url */,\n\t\t\t);\n\t\t\tpath = Features;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_5 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_6 /* Package.swift */,\n\t\t\t\tOBJ_7 /* Sources */,\n\t\t\t\tOBJ_242 /* Tests */,\n\t\t\t\tOBJ_243 /* Products */,\n\t\t\t\tOBJ_245 /* tools */,\n\t\t\t\tOBJ_246 /* Example */,\n\t\t\t\tOBJ_247 /* Cloudinary */,\n\t\t\t\tOBJ_248 /* LICENSE */,\n\t\t\t\tOBJ_249 /* CHANGELOG.md */,\n\t\t\t\tOBJ_250 /* Cloudinary.podspec */,\n\t\t\t\tOBJ_251 /* README.md */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_7 /* Sources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_8 /* Core */,\n\t\t\t\tOBJ_226 /* ios */,\n\t\t\t);\n\t\t\tname = Sources;\n\t\t\tpath = Cloudinary/Classes;\n\t\t\tsourceTree = SOURCE_ROOT;\n\t\t};\n\t\tOBJ_72 /* Downloader */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_73 /* CLDDownloader.swift */,\n\t\t\t);\n\t\t\tpath = Downloader;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_74 /* Helpers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_75 /* CLDBaseNetworkObject.swift */,\n\t\t\t\tOBJ_76 /* CLDConditionExpression.swift */,\n\t\t\t\tOBJ_77 /* CLDDefinitions.swift */,\n\t\t\t\tOBJ_78 /* CLDExpression.swift */,\n\t\t\t\tOBJ_79 /* CLDOperators.swift */,\n\t\t\t\tOBJ_80 /* CLDTransformation.swift */,\n\t\t\t\tOBJ_81 /* CLDVariable.swift */,\n\t\t\t\tOBJ_82 /* Layers */,\n\t\t\t\tOBJ_87 /* RequestParams */,\n\t\t\t\tOBJ_91 /* Requests */,\n\t\t\t\tOBJ_93 /* Results */,\n\t\t\t);\n\t\t\tpath = Helpers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_8 /* Core */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_9 /* BaseNetwork */,\n\t\t\t\tOBJ_24 /* CLDCloudinary.swift */,\n\t\t\t\tB694AAEB2B308AF100075041 /* CLDAnalytics.swift */,\n\t\t\t\tOBJ_25 /* CLDCompatibility.swift */,\n\t\t\t\tOBJ_26 /* CLDConfiguration.swift */,\n\t\t\t\tOBJ_27 /* CLDEagerTransformation.swift */,\n\t\t\t\tOBJ_28 /* CLDResponsiveParams.swift */,\n\t\t\t\tOBJ_29 /* Features */,\n\t\t\t\tOBJ_201 /* Network */,\n\t\t\t\tOBJ_213 /* Utils */,\n\t\t\t);\n\t\t\tpath = Core;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_82 /* Layers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_83 /* CLDFetchLayer.swift */,\n\t\t\t\tOBJ_84 /* CLDLayer.swift */,\n\t\t\t\tOBJ_85 /* CLDSubtitlesLayer.swift */,\n\t\t\t\tOBJ_86 /* CLDTextLayer.swift */,\n\t\t\t);\n\t\t\tpath = Layers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_87 /* RequestParams */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_88 /* CLDRequestParams.swift */,\n\t\t\t\tOBJ_89 /* Helpers */,\n\t\t\t);\n\t\t\tpath = RequestParams;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_89 /* Helpers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_90 /* CLDRequestParamsHelpers.swift */,\n\t\t\t);\n\t\t\tpath = Helpers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_9 /* BaseNetwork */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_10 /* CLDNConvertible.swift */,\n\t\t\t\tOBJ_11 /* CLDNError.swift */,\n\t\t\t\tOBJ_12 /* CLDNMultipartFormData.swift */,\n\t\t\t\tOBJ_13 /* CLDNParameterEncoding.swift */,\n\t\t\t\tOBJ_14 /* CLDNRequest.swift */,\n\t\t\t\tOBJ_15 /* CLDNResponse.swift */,\n\t\t\t\tOBJ_16 /* CLDNResponseSerialization.swift */,\n\t\t\t\tOBJ_17 /* CLDNResult.swift */,\n\t\t\t\tOBJ_18 /* CLDNSessionDelegate.swift */,\n\t\t\t\tOBJ_19 /* CLDNSessionManager.swift */,\n\t\t\t\tOBJ_20 /* CLDNTaskDelegate.swift */,\n\t\t\t\tOBJ_21 /* CLDNTimeline.swift */,\n\t\t\t\tOBJ_22 /* CLDNValidation.swift */,\n\t\t\t\tOBJ_23 /* DispatchQueue+Cloudinary.swift */,\n\t\t\t);\n\t\t\tpath = BaseNetwork;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_91 /* Requests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_92 /* CLDRequest.swift */,\n\t\t\t);\n\t\t\tpath = Requests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_93 /* Results */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_94 /* CLDBaseResult.swift */,\n\t\t\t\tOBJ_95 /* Helpers */,\n\t\t\t);\n\t\t\tpath = Results;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_95 /* Helpers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_96 /* AccessibilityAnalysis */,\n\t\t\t\tOBJ_99 /* CLDBoundingBox.swift */,\n\t\t\t\tOBJ_100 /* CLDDetection.swift */,\n\t\t\t\tOBJ_101 /* CLDFace.swift */,\n\t\t\t\tOBJ_102 /* CLDInfo.swift */,\n\t\t\t\tOBJ_103 /* CLDOcr */,\n\t\t\t\tOBJ_117 /* CLDQualityAnalysis */,\n\t\t\t\tOBJ_119 /* CLDRekognitionFace.swift */,\n\t\t\t\tOBJ_120 /* CommonResultKeys.swift */,\n\t\t\t);\n\t\t\tpath = Helpers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tOBJ_96 /* AccessibilityAnalysis */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tOBJ_97 /* CLDAccessibilityAnalysisResult.swift */,\n\t\t\t\tOBJ_98 /* CLDColorblindAccessibilityAnalysisResult.swift */,\n\t\t\t);\n\t\t\tpath = AccessibilityAnalysis;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t\"Cloudinary::Cloudinary\" /* Cloudinary */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = OBJ_253 /* Build configuration list for PBXNativeTarget \"Cloudinary\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tOBJ_256 /* Sources */,\n\t\t\t\tOBJ_436 /* Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Cloudinary;\n\t\t\tproductName = Cloudinary;\n\t\t\tproductReference = \"Cloudinary::Cloudinary::Product\" /* Cloudinary.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t\"Cloudinary::SwiftPMPackageDescription\" /* CloudinaryPackageDescription */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = OBJ_438 /* Build configuration list for PBXNativeTarget \"CloudinaryPackageDescription\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tOBJ_441 /* Sources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = CloudinaryPackageDescription;\n\t\t\tproductName = CloudinaryPackageDescription;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tOBJ_1 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftMigration = 9999;\n\t\t\t\tLastUpgradeCheck = 9999;\n\t\t\t};\n\t\t\tbuildConfigurationList = OBJ_2 /* Build configuration list for PBXProject \"Cloudinary\" */;\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);\n\t\t\tmainGroup = OBJ_5;\n\t\t\tproductRefGroup = OBJ_243 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t\"Cloudinary::Cloudinary\" /* Cloudinary */,\n\t\t\t\t\"Cloudinary::SwiftPMPackageDescription\" /* CloudinaryPackageDescription */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tOBJ_256 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 0;\n\t\t\tfiles = (\n\t\t\t\tOBJ_257 /* CLDNConvertible.swift in Sources */,\n\t\t\t\tOBJ_258 /* CLDNError.swift in Sources */,\n\t\t\t\tOBJ_259 /* CLDNMultipartFormData.swift in Sources */,\n\t\t\t\tOBJ_260 /* CLDNParameterEncoding.swift in Sources */,\n\t\t\t\tOBJ_261 /* CLDNRequest.swift in Sources */,\n\t\t\t\tOBJ_262 /* CLDNResponse.swift in Sources */,\n\t\t\t\tOBJ_263 /* CLDNResponseSerialization.swift in Sources */,\n\t\t\t\tOBJ_264 /* CLDNResult.swift in Sources */,\n\t\t\t\tOBJ_265 /* CLDNSessionDelegate.swift in Sources */,\n\t\t\t\tOBJ_266 /* CLDNSessionManager.swift in Sources */,\n\t\t\t\tOBJ_267 /* CLDNTaskDelegate.swift in Sources */,\n\t\t\t\tOBJ_268 /* CLDNTimeline.swift in Sources */,\n\t\t\t\tOBJ_269 /* CLDNValidation.swift in Sources */,\n\t\t\t\tOBJ_270 /* DispatchQueue+Cloudinary.swift in Sources */,\n\t\t\t\tOBJ_271 /* CLDCloudinary.swift in Sources */,\n\t\t\t\tOBJ_272 /* CLDCompatibility.swift in Sources */,\n\t\t\t\tOBJ_273 /* CLDConfiguration.swift in Sources */,\n\t\t\t\tOBJ_274 /* CLDEagerTransformation.swift in Sources */,\n\t\t\t\tOBJ_275 /* CLDResponsiveParams.swift in Sources */,\n\t\t\t\tB694AAF12B308B9D00075041 /* VideoEventsManager.swift in Sources */,\n\t\t\t\tOBJ_304 /* CLDDownloader.swift in Sources */,\n\t\t\t\tOBJ_305 /* CLDBaseNetworkObject.swift in Sources */,\n\t\t\t\tOBJ_306 /* CLDConditionExpression.swift in Sources */,\n\t\t\t\tOBJ_307 /* CLDDefinitions.swift in Sources */,\n\t\t\t\tOBJ_308 /* CLDExpression.swift in Sources */,\n\t\t\t\tOBJ_309 /* CLDOperators.swift in Sources */,\n\t\t\t\tOBJ_310 /* CLDTransformation.swift in Sources */,\n\t\t\t\tOBJ_311 /* CLDVariable.swift in Sources */,\n\t\t\t\tB6B4C49C2C56100600C9B604 /* CLDVideoTranscode.swift in Sources */,\n\t\t\t\tOBJ_312 /* CLDFetchLayer.swift in Sources */,\n\t\t\t\tOBJ_313 /* CLDLayer.swift in Sources */,\n\t\t\t\tOBJ_314 /* CLDSubtitlesLayer.swift in Sources */,\n\t\t\t\tOBJ_315 /* CLDTextLayer.swift in Sources */,\n\t\t\t\tOBJ_316 /* CLDRequestParams.swift in Sources */,\n\t\t\t\tOBJ_317 /* CLDRequestParamsHelpers.swift in Sources */,\n\t\t\t\tOBJ_318 /* CLDRequest.swift in Sources */,\n\t\t\t\tB6C2D4862A724C4200AA0039 /* CLDVideoPlayer.swift in Sources */,\n\t\t\t\tOBJ_319 /* CLDBaseResult.swift in Sources */,\n\t\t\t\tOBJ_320 /* CLDAccessibilityAnalysisResult.swift in Sources */,\n\t\t\t\tOBJ_321 /* CLDColorblindAccessibilityAnalysisResult.swift in Sources */,\n\t\t\t\tOBJ_322 /* CLDBoundingBox.swift in Sources */,\n\t\t\t\tOBJ_323 /* CLDDetection.swift in Sources */,\n\t\t\t\tOBJ_324 /* CLDFace.swift in Sources */,\n\t\t\t\tOBJ_325 /* CLDInfo.swift in Sources */,\n\t\t\t\tOBJ_326 /* CLDAdvOcrResult.swift in Sources */,\n\t\t\t\tOBJ_327 /* CLDOcrBlockResult.swift in Sources */,\n\t\t\t\tOBJ_328 /* CLDOcrBoundindBlockResult.swift in Sources */,\n\t\t\t\tOBJ_329 /* CLDOcrDataResult.swift in Sources */,\n\t\t\t\tOBJ_330 /* CLDOcrDetectedLanguagesResult.swift in Sources */,\n\t\t\t\tOBJ_331 /* CLDOcrFullTextAnnotationResult.swift in Sources */,\n\t\t\t\tOBJ_332 /* CLDOcrPageResult.swift in Sources */,\n\t\t\t\tOBJ_333 /* CLDOcrParagraphResult.swift in Sources */,\n\t\t\t\tOBJ_334 /* CLDOcrPropertyResult.swift in Sources */,\n\t\t\t\tOBJ_335 /* CLDOcrResult.swift in Sources */,\n\t\t\t\tOBJ_336 /* CLDOcrSymbolResult.swift in Sources */,\n\t\t\t\tOBJ_337 /* CLDOcrTextAnnotationResult.swift in Sources */,\n\t\t\t\tB6B4C49A2C560FEE00C9B604 /* CLDVideoPreprocessChain.swift in Sources */,\n\t\t\t\tOBJ_338 /* CLDOcrWordResult.swift in Sources */,\n\t\t\t\tOBJ_339 /* CLDQualityAnalysis.swift in Sources */,\n\t\t\t\tOBJ_340 /* CLDRekognitionFace.swift in Sources */,\n\t\t\t\tOBJ_341 /* CommonResultKeys.swift in Sources */,\n\t\t\t\tOBJ_342 /* CLDManagementApi.swift in Sources */,\n\t\t\t\tOBJ_343 /* CLDDeleteRequest.swift in Sources */,\n\t\t\t\tOBJ_344 /* CLDExplicitRequest.swift in Sources */,\n\t\t\t\tOBJ_345 /* CLDExplodeRequest.swift in Sources */,\n\t\t\t\tOBJ_346 /* CLDMultiRequest.swift in Sources */,\n\t\t\t\tOBJ_347 /* CLDRenameRequest.swift in Sources */,\n\t\t\t\tOBJ_348 /* CLDSpriteRequest.swift in Sources */,\n\t\t\t\tOBJ_349 /* CLDTagRequest.swift in Sources */,\n\t\t\t\tOBJ_350 /* CLDTextRequest.swift in Sources */,\n\t\t\t\tOBJ_351 /* CLDDeleteByTokenRequestParams.swift in Sources */,\n\t\t\t\tOBJ_352 /* CLDDestroyRequestParams.swift in Sources */,\n\t\t\t\tOBJ_353 /* CLDExplicitRequestParams.swift in Sources */,\n\t\t\t\tOBJ_354 /* CLDExplodeRequestParams.swift in Sources */,\n\t\t\t\tOBJ_355 /* CLDMultiRequestParams.swift in Sources */,\n\t\t\t\tOBJ_356 /* CLDRenameRequestParams.swift in Sources */,\n\t\t\t\tOBJ_357 /* CLDSpriteRequestParams.swift in Sources */,\n\t\t\t\tOBJ_358 /* CLDTagsRequestParams.swift in Sources */,\n\t\t\t\tOBJ_359 /* CLDTextRequestParams.swift in Sources */,\n\t\t\t\tOBJ_360 /* CLDDeleteResult.swift in Sources */,\n\t\t\t\tOBJ_361 /* CLDExplicitResult.swift in Sources */,\n\t\t\t\tOBJ_362 /* CLDExplodeResult.swift in Sources */,\n\t\t\t\tOBJ_363 /* CLDMultiResult.swift in Sources */,\n\t\t\t\tOBJ_364 /* CLDRenameResult.swift in Sources */,\n\t\t\t\tOBJ_365 /* CLDSpriteResult.swift in Sources */,\n\t\t\t\tOBJ_366 /* CLDTagResult.swift in Sources */,\n\t\t\t\tOBJ_367 /* CLDTextResult.swift in Sources */,\n\t\t\t\tOBJ_368 /* CLDUploaderWidget.swift in Sources */,\n\t\t\t\tOBJ_369 /* CLDCropOverlayView.swift in Sources */,\n\t\t\t\tOBJ_370 /* CLDCropScrollView.swift in Sources */,\n\t\t\t\tOBJ_371 /* CLDCropScrollViewController.swift in Sources */,\n\t\t\t\tOBJ_372 /* CLDCropView.swift in Sources */,\n\t\t\t\tOBJ_373 /* CLDCropViewCalculator.swift in Sources */,\n\t\t\t\tOBJ_374 /* CLDCropViewUIManager.swift in Sources */,\n\t\t\t\tOBJ_375 /* CLDWidgetConfiguration.swift in Sources */,\n\t\t\t\tOBJ_376 /* CLDWidgetAssetContainer.swift in Sources */,\n\t\t\t\tOBJ_377 /* CLDWidgetPreviewCollectionCell.swift in Sources */,\n\t\t\t\tOBJ_378 /* BackIconInstructions.swift in Sources */,\n\t\t\t\tB694AAEC2B308AF100075041 /* CLDAnalytics.swift in Sources */,\n\t\t\t\tOBJ_379 /* CropIconInstructions.swift in Sources */,\n\t\t\t\tOBJ_380 /* CropRotateIconInstructions.swift in Sources */,\n\t\t\t\tOBJ_381 /* DoneIconInstructions.swift in Sources */,\n\t\t\t\tOBJ_382 /* RatioLockedIconInstructions.swift in Sources */,\n\t\t\t\tOBJ_383 /* RatioOpenedIconInstructions.swift in Sources */,\n\t\t\t\tOBJ_384 /* RotateIconInstructions.swift in Sources */,\n\t\t\t\tOBJ_385 /* CLDDisplayLinkObserver.swift in Sources */,\n\t\t\t\tOBJ_386 /* CLDVideoControlsState.swift in Sources */,\n\t\t\t\tOBJ_387 /* CLDVideoControlsView.swift in Sources */,\n\t\t\t\tOBJ_388 /* CLDVideoHiddenAndPausedState.swift in Sources */,\n\t\t\t\tB694AAEF2B308B8400075041 /* VideoAnalytics.swift in Sources */,\n\t\t\t\tOBJ_389 /* CLDVideoHiddenAndPlayingState.swift in Sources */,\n\t\t\t\tOBJ_390 /* CLDVideoPlayerView.swift in Sources */,\n\t\t\t\tOBJ_391 /* CLDVideoShownAndPausedState.swift in Sources */,\n\t\t\t\tOBJ_392 /* CLDVideoShownAndPlayingState.swift in Sources */,\n\t\t\t\tOBJ_393 /* CLDVideoView.swift in Sources */,\n\t\t\t\tOBJ_394 /* CLDWidgetEditViewController.swift in Sources */,\n\t\t\t\tOBJ_395 /* CLDWidgetPreviewViewController.swift in Sources */,\n\t\t\t\tB690BF5E2BC55992007117AC /* HTTPStatusCode.swift in Sources */,\n\t\t\t\tOBJ_396 /* CLDWidgetViewController.swift in Sources */,\n\t\t\t\tOBJ_397 /* CLDUploader.swift in Sources */,\n\t\t\t\tOBJ_398 /* CLDPreprocessChain.swift in Sources */,\n\t\t\t\tOBJ_399 /* CLDUploadRequestParams.swift in Sources */,\n\t\t\t\tOBJ_400 /* CLDDefaultUploadRequest.swift in Sources */,\n\t\t\t\tOBJ_401 /* CLDUploadRequest.swift in Sources */,\n\t\t\t\tOBJ_402 /* CLDUploadRequestWrapper.swift in Sources */,\n\t\t\t\tOBJ_403 /* CLDUploadResult.swift in Sources */,\n\t\t\t\tOBJ_404 /* CLDUrl.swift in Sources */,\n\t\t\t\tOBJ_405 /* CLDNetworkAdapter.swift in Sources */,\n\t\t\t\tOBJ_406 /* CLDDefaultNetworkAdapter.swift in Sources */,\n\t\t\t\tOBJ_407 /* CLDNetworkCoordinator.swift in Sources */,\n\t\t\t\tOBJ_408 /* CLDAsyncNetworkUploadRequest.swift in Sources */,\n\t\t\t\tB6B4C4A12C5615CF00C9B604 /* CLDVideoPreprocessHelpers.swift in Sources */,\n\t\t\t\tOBJ_409 /* CLDErrorRequest.swift in Sources */,\n\t\t\t\tOBJ_410 /* CLDGenericNetworkRequest.swift in Sources */,\n\t\t\t\tOBJ_411 /* CLDNetworkDataRequestImpl.swift in Sources */,\n\t\t\t\tOBJ_412 /* CLDNetworkDownloadRequest.swift in Sources */,\n\t\t\t\tOBJ_413 /* CLDNetworkUploadRequest.swift in Sources */,\n\t\t\t\tOBJ_414 /* CLDBuildParamsUtils.swift in Sources */,\n\t\t\t\tOBJ_415 /* CLDCryptoUtils.swift in Sources */,\n\t\t\t\tOBJ_416 /* CLDDictionaryUtils.swift in Sources */,\n\t\t\t\tOBJ_417 /* CLDError.swift in Sources */,\n\t\t\t\tOBJ_418 /* CLDFileUtils.swift in Sources */,\n\t\t\t\tOBJ_420 /* CLDImageGenerator.swift in Sources */,\n\t\t\t\tOBJ_421 /* CLDImageUtils.swift in Sources */,\n\t\t\t\tOBJ_422 /* CLDJsonUtils.swift in Sources */,\n\t\t\t\tOBJ_423 /* CLDLogManager.swift in Sources */,\n\t\t\t\tOBJ_424 /* CLDStringUtils.swift in Sources */,\n\t\t\t\tOBJ_425 /* CLDTransformation+Ios.swift in Sources */,\n\t\t\t\tOBJ_426 /* ExtensionCLDDownloader.swift in Sources */,\n\t\t\t\tOBJ_427 /* UIButton+Cloudinary.swift in Sources */,\n\t\t\t\tOBJ_428 /* UIImageView+Cloudinary.swift in Sources */,\n\t\t\t\tOBJ_429 /* UIView+Cloudinary.swift in Sources */,\n\t\t\t\tOBJ_430 /* CLDFetchAssetRequestImpl.swift in Sources */,\n\t\t\t\tOBJ_431 /* CLDFetchImageRequestImpl.swift in Sources */,\n\t\t\t\tOBJ_432 /* CLDResponsiveViewHelper.swift in Sources */,\n\t\t\t\tOBJ_433 /* CLDUIImageView.swift in Sources */,\n\t\t\t\tOBJ_434 /* CLDImagePreprocessChain.swift in Sources */,\n\t\t\t\tOBJ_435 /* CLDPreprocessHelpers.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tOBJ_441 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 0;\n\t\t\tfiles = (\n\t\t\t\tOBJ_442 /* Package.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin XCBuildConfiguration section */\n\t\tOBJ_254 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDRIVERKIT_DEPLOYMENT_TARGET = 19.0;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PLATFORM_DIR)/Developer/Library/Frameworks\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tINFOPLIST_FILE = Cloudinary.xcodeproj/Cloudinary_Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tOTHER_CFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_LDFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_SWIFT_FLAGS = \"$(inherited)\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = Cloudinary;\n\t\t\t\tPRODUCT_MODULE_NAME = \"$(TARGET_NAME:c99extidentifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME:c99extidentifier)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"$(inherited)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGET_NAME = Cloudinary;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 2.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tOBJ_255 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDRIVERKIT_DEPLOYMENT_TARGET = 19.0;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PLATFORM_DIR)/Developer/Library/Frameworks\",\n\t\t\t\t);\n\t\t\t\tHEADER_SEARCH_PATHS = \"$(inherited)\";\n\t\t\t\tINFOPLIST_FILE = Cloudinary.xcodeproj/Cloudinary_Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx\";\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tOTHER_CFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_LDFLAGS = \"$(inherited)\";\n\t\t\t\tOTHER_SWIFT_FLAGS = \"$(inherited)\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = Cloudinary;\n\t\t\t\tPRODUCT_MODULE_NAME = \"$(TARGET_NAME:c99extidentifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME:c99extidentifier)\";\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"$(inherited)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGET_NAME = Cloudinary;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 9.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 2.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tOBJ_3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tENABLE_NS_ASSERTIONS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"SWIFT_PACKAGE=1\",\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_SWIFT_FLAGS = \"$(inherited) -DXcode\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphonesimulator iphoneos\";\n\t\t\t\tSUPPORTS_MACCATALYST = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"$(inherited) SWIFT_PACKAGE DEBUG\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tUSE_HEADERMAP = NO;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tOBJ_4 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tCOPY_PHASE_STRIP = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = s;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"SWIFT_PACKAGE=1\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.10;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tOTHER_SWIFT_FLAGS = \"$(inherited) -DXcode\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphonesimulator iphoneos\";\n\t\t\t\tSUPPORTS_MACCATALYST = YES;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = \"$(inherited) SWIFT_PACKAGE\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tUSE_HEADERMAP = NO;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tOBJ_439 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tLD = /usr/bin/true;\n\t\t\t\tOTHER_SWIFT_FLAGS = \"-swift-version 5 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/ManifestAPI -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk -package-description-version 5.1.0\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tOBJ_440 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tLD = /usr/bin/true;\n\t\t\t\tOTHER_SWIFT_FLAGS = \"-swift-version 5 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/ManifestAPI -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.1.sdk -package-description-version 5.1.0\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tOBJ_2 /* Build configuration list for PBXProject \"Cloudinary\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tOBJ_3 /* Debug */,\n\t\t\t\tOBJ_4 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tOBJ_253 /* Build configuration list for PBXNativeTarget \"Cloudinary\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tOBJ_254 /* Debug */,\n\t\t\t\tOBJ_255 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tOBJ_438 /* Build configuration list for PBXNativeTarget \"CloudinaryPackageDescription\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tOBJ_439 /* Debug */,\n\t\t\t\tOBJ_440 /* 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 = OBJ_1 /* Project object */;\n}\n"
  },
  {
    "path": "Cloudinary.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>"
  },
  {
    "path": "Cloudinary.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Cloudinary.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>\n    <false/>\n</dict>\n</plist>"
  },
  {
    "path": "Cloudinary.xcodeproj/xcshareddata/xcschemes/Cloudinary-Package.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"9999\"\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 = \"Cloudinary::Cloudinary\"\n               BuildableName = \"Cloudinary.framework\"\n               BlueprintName = \"Cloudinary\"\n               ReferencedContainer = \"container:Cloudinary.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   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Example/Cloudinary/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 11/09/2023.\n//\n\nimport UIKit\n\n@main\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n\n\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        // Override point for customization after application launch.\n        return true\n    }\n\n    func applicationDidEnterBackground(_ application: UIApplication) {\n        CoreDataHelper.shared.saveContext()\n    }\n\n    func applicationWillTerminate(_ application: UIApplication) {\n        CoreDataHelper.shared.saveContext()\n    }\n}\n\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"app_icon 1.heic\",\n      \"idiom\" : \"universal\",\n      \"platform\" : \"ios\",\n      \"size\" : \"1024x1024\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/Inner/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/Inner/ski.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"smart-crop-4 (4) 1.png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/Inner/sofa.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"sofa.png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/Video/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/Video/instagram.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Group.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/Video/tiktok.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"tiktok-white-icon.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/Video/youtube.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Youtube_shorts_icon 1.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/background_normalizing.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"background_normalizing.png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/color_alternation.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"color_alternation.png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/delivery-city.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"optimization_hero_gezokr.png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/localization_branding.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"localization_branding.png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Delivery/smart_cropping.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Rectangle 3 (1).png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Upload/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Upload/question_mark.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"ic_help_outline_24px.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Upload/upload_missing.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"picturepile-4.png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_bar_icon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Group 5.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_comments.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Group 2.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_discover.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Vector (3).svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_home.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Vector (2).svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_inbox.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Group 3.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_like.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Vector (4).svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_more.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"icon_more.png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_music.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"music animation.png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_note.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Vector (1).svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_share.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Vector (5).svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Video/TikTok/tiktok_social_icon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Avatar.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Widgets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/Widgets/house.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Frame_871_ao5o4r_2_viaeyi.heic\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/back_arrow.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"left _arrow.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/car-speed-limiter.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"car-speed-limiter 1.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true,\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/cloudinary_logo.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Layer 1.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/info_icon.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"info_icon.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/splash.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Image.png\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/splash_without_logo.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Splashwithoutlogo.jpg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/upload.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"upload-outline 1.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true,\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/video.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"Frame 12.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true,\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Assets.xcassets/widgets.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"filename\" : \"widgets-outline 1.svg\",\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"properties\" : {\n    \"preserves-vector-representation\" : true,\n    \"template-rendering-intent\" : \"template\"\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/CldModel.xcdatamodeld/CldModel.xcdatamodel/contents",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<model type=\"com.apple.IDECoreDataModeler.DataModel\" documentVersion=\"1.0\" lastSavedToolsVersion=\"12141\"\n       systemVersion=\"16G29\" minimumToolsVersion=\"Automatic\" sourceLanguage=\"Swift\"\n       userDefinedModelVersionIdentifier=\"\">\n    <entity name=\"CLDResource\" representedClassName=\"CLDResource\" syncable=\"YES\" codeGenerationType=\"class\">\n        <attribute name=\"deleteToken\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"lastErrorCode\" optional=\"YES\" attributeType=\"Integer 16\" defaultValueString=\"0\"\n                   usesScalarValueType=\"YES\" syncable=\"YES\"/>\n        <attribute name=\"lastErrorText\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"localPath\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"name\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"publicId\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"resourceType\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"status\" optional=\"YES\" attributeType=\"String\" syncable=\"YES\"/>\n        <attribute name=\"statusTimestamp\" optional=\"YES\" attributeType=\"Date\" usesScalarValueType=\"NO\" syncable=\"YES\"/>\n    </entity>\n    <elements>\n        <element name=\"CLDResource\" positionX=\"-63\" positionY=\"-18\" width=\"128\" height=\"180\"/>\n    </elements>\n</model>"
  },
  {
    "path": "Example/Cloudinary/Cloudinary_Example-Bridging-Header.h",
    "content": "//\n//  Use this file to import your target's public headers that you would like to expose to Swift.\n//\n\n"
  },
  {
    "path": "Example/Cloudinary/Colors.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Colors.xcassets/gradient-first.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xC5\",\n          \"green\" : \"0x48\",\n          \"red\" : \"0x34\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xC5\",\n          \"green\" : \"0x48\",\n          \"red\" : \"0x34\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Colors.xcassets/gradient-second.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xFA\",\n          \"green\" : \"0xBB\",\n          \"red\" : \"0x28\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xFA\",\n          \"green\" : \"0xBB\",\n          \"red\" : \"0x28\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Colors.xcassets/primary.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xF7\",\n          \"green\" : \"0x98\",\n          \"red\" : \"0x46\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xF7\",\n          \"green\" : \"0x98\",\n          \"red\" : \"0x46\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Colors.xcassets/secondary.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0x5A\",\n          \"green\" : \"0x47\",\n          \"red\" : \"0x3F\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0x5A\",\n          \"green\" : \"0x47\",\n          \"red\" : \"0x3F\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Colors.xcassets/size_green.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xAE\",\n          \"green\" : \"0xFC\",\n          \"red\" : \"0xB2\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xAE\",\n          \"green\" : \"0xFC\",\n          \"red\" : \"0xB2\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Colors.xcassets/size_red.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0x59\",\n          \"green\" : \"0x59\",\n          \"red\" : \"0xFF\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0x59\",\n          \"green\" : \"0x59\",\n          \"red\" : \"0xFF\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Colors.xcassets/surface.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0x2D\",\n          \"green\" : \"0x24\",\n          \"red\" : \"0x20\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0x2D\",\n          \"green\" : \"0x24\",\n          \"red\" : \"0x20\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Colors.xcassets/text_not_selected.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xFE\",\n          \"green\" : \"0xFF\",\n          \"red\" : \"0xFF\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    },\n    {\n      \"appearances\" : [\n        {\n          \"appearance\" : \"luminosity\",\n          \"value\" : \"dark\"\n        }\n      ],\n      \"color\" : {\n        \"color-space\" : \"srgb\",\n        \"components\" : {\n          \"alpha\" : \"1.000\",\n          \"blue\" : \"0xFE\",\n          \"green\" : \"0xFF\",\n          \"red\" : \"0xFF\"\n        }\n      },\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Base/BaseViewController.swift",
    "content": "//\n//  BaseViewController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 04/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass BaseViewController: UIViewController {\n    @IBOutlet weak var vwContainer: UIView!\n    @IBOutlet weak var lbTitle: UILabel!\n    @IBOutlet weak var vwBack: UIView!\n    var type: BaseControllerType!\n    var innerIndex: Int = 0\n\n    var currentController: UIViewController!\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setTitle()\n        setController()\n        setBackButton()\n    }\n\n    private func setBackButton() {\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(backClicked))\n        vwBack.addGestureRecognizer(tapGesture)\n    }\n\n    private func setTitle() {\n        switch type {\n        case .Optimization:\n            lbTitle.text = \"Optimization\"\n            break\n        case .Transform:\n            lbTitle.text = \"Transform\"\n            break\n        case .Upload:\n            lbTitle.text = \"Upload\"\n            break\n        case .UploadLarge:\n            lbTitle.text = \"Upload Large\"\n            break\n        case .FetchUpload:\n            lbTitle.text = \"Fetch Upload\"\n            break\n        case .UploadWidget:\n            lbTitle.text = \"Upload Widget\"\n            break\n        case .ImageWidget:\n            lbTitle.text = \"Image Widget\"\n            break\n        case .UseCases:\n            lbTitle.text = \"Use Cases\"\n            break\n        case .none:\n            break\n        }\n    }\n\n    private func setController() {\n            switch type {\n            case .Optimization:\n                currentController = UIStoryboard(name: \"Optimization\", bundle: nil).instantiateViewController(identifier: \"OptimizationViewController\") as! OptimizationViewController\n                currentController.view.frame = vwContainer.bounds\n                (currentController as! OptimizationViewController).type = .Optimization\n                addChild(currentController)\n                vwContainer.addSubview(currentController.view)\n                currentController.didMove(toParent: self)\n            case .Transform:\n                currentController = UIStoryboard(name: \"Transform\", bundle: nil).instantiateViewController(identifier: \"TransformViewController\") as! TransformViewController\n                (currentController as! TransformViewController).innerIndex = innerIndex\n                currentController.view.frame = vwContainer.bounds\n                addChild(currentController)\n                vwContainer.addSubview(currentController.view)\n                currentController.didMove(toParent: self)\n            case .UseCases:\n                currentController = UIStoryboard(name: \"UseCases\", bundle: nil).instantiateViewController(identifier: \"UseCasesViewController\") as! UseCasesViewController\n                currentController.view.frame = vwContainer.bounds\n                (currentController as! UseCasesViewController).innerIndex = innerIndex\n                addChild(currentController)\n                vwContainer.addSubview(currentController.view)\n                currentController.didMove(toParent: self)\n            case .Upload:\n                currentController = (UIStoryboard(name: \"UploadChoice\", bundle: nil).instantiateViewController(identifier: \"UploadChoiceController\") as! UploadChoiceController)\n                currentController.view.frame = vwContainer.bounds\n                (currentController as! UploadChoiceController).type = .Upload\n                addChild(currentController)\n                vwContainer.addSubview(currentController.view)\n                currentController.didMove(toParent: self)\n            case .UploadLarge:\n                currentController = (UIStoryboard(name: \"UploadChoice\", bundle: nil).instantiateViewController(identifier: \"UploadChoiceController\") as! UploadChoiceController)\n                currentController.view.frame = vwContainer.bounds\n                (currentController as! UploadChoiceController).type = .UploadLarge\n                addChild(currentController)\n                vwContainer.addSubview(currentController.view)\n                currentController.didMove(toParent: self)\n            case .FetchUpload:\n                 currentController = UIStoryboard(name: \"Optimization\", bundle: nil).instantiateViewController(identifier: \"OptimizationViewController\") as! OptimizationViewController\n                currentController.view.frame = vwContainer.bounds\n                (currentController as! OptimizationViewController).publicId = \"https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Leonardo_da_Vinci_%281452-1519%29_-_The_Last_Supper_%281495-1498%29.jpg/1600px-Leonardo_da_Vinci_%281452-1519%29_-_The_Last_Supper_%281495-1498%29.jpg?20150402075721\"\n                (currentController as! OptimizationViewController).type = .FetchUpload\n                addChild(currentController)\n                vwContainer.addSubview(currentController.view)\n                currentController.didMove(toParent: self)\n            case .UploadWidget:\n                if (currentController == nil || (currentController as? UploadWidgetViewController == nil)) {\n                    currentController = UIStoryboard(name: \"UploadWidget\", bundle: nil).instantiateViewController(identifier: \"UploadWidgetViewController\")\n                    currentController.view.frame = vwContainer.bounds\n                    addChild(currentController)\n                    vwContainer.addSubview(currentController.view)\n                    currentController.didMove(toParent: self)\n                }\n            case .ImageWidget:\n                 currentController = UIStoryboard(name: \"ImageWidget\", bundle: nil).instantiateViewController(identifier: \"ImageWidgetViewController\")\n                currentController.view.frame = vwContainer.bounds\n                addChild(currentController)\n                vwContainer.addSubview(currentController.view)\n        case .none:\n            break\n        }\n    }\n\n    @objc private func backClicked() {\n        self.dismiss(animated: true)\n    }\n}\n\nenum BaseControllerType {\n    case Optimization\n    case Transform\n    case Upload\n    case UploadLarge\n    case FetchUpload\n    case UploadWidget\n    case ImageWidget\n    case UseCases\n}\npublic enum UploadViewType {\n    case Upload\n    case UploadLarge\n    case UploadWidget\n}\n\npublic enum OptimizationViewType {\n    case Optimization\n    case FetchUpload\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/DeliveryViewController.swift",
    "content": "//\n//  DeliveryViewController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 28/12/2023.\n//\n\nimport Foundation\nimport UIKit\n\nclass DeliveryViewController: UIViewController {\n    @IBOutlet weak var vwOptimization: UIView!\n    @IBOutlet weak var vwTransform: UIView!\n    @IBOutlet weak var vwUseCases: UIView!\n    @IBOutlet weak var lbTitle: UILabel!\n    @IBOutlet weak var cvTransformation: UICollectionView!\n    @IBOutlet weak var cvUseCases: UICollectionView!\n    \n    var transfromationCollectionController: DeliveryTransformCollectionController!\n    var useCasesCollectionController: DeliveryUseCasesCollectionController!\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        setOptimizationView()\n        setTransformationCollectionView()\n        setUseCasesCollectionView()\n    }\n\n    private func setOptimizationView() {\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(optimizationClicked))\n\n        vwOptimization.addGestureRecognizer(tapGesture)\n    }\n\n    @objc private func optimizationClicked() {\n        if let controller = UIStoryboard(name: \"Base\", bundle: nil).instantiateViewController(identifier: \"BaseViewController\") as? BaseViewController {\n            controller.type = .Optimization\n            controller.modalPresentationStyle = .fullScreen\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n\n    @objc private func transformClicked(_ index: Int) {\n        if let controller = UIStoryboard(name: \"Base\", bundle: nil).instantiateViewController(identifier: \"BaseViewController\") as? BaseViewController {\n            controller.type = .Transform\n            controller.innerIndex = index\n            controller.modalPresentationStyle = .fullScreen\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n\n    @objc private func useCasesClicked(_ index: Int) {\n        if let controller = UIStoryboard(name: \"Base\", bundle: nil).instantiateViewController(identifier: \"BaseViewController\") as? BaseViewController {\n            controller.innerIndex = index\n            controller.type = .UseCases\n            controller.modalPresentationStyle = .fullScreen\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n\n    private func setTransformationCollectionView() {\n        transfromationCollectionController = DeliveryTransformCollectionController(self)\n        cvTransformation.dataSource = transfromationCollectionController\n        cvTransformation.delegate = transfromationCollectionController\n    }\n\n    private func setUseCasesCollectionView() {\n        useCasesCollectionController = DeliveryUseCasesCollectionController(self)\n        cvUseCases.delegate = useCasesCollectionController\n        cvUseCases.dataSource = useCasesCollectionController\n    }\n}\n\nextension DeliveryViewController: DeliveryTransformCollectionDelegate {\n    func transformCellSelected(_ index: Int) {\n        transformClicked(index)\n    }\n}\n\nextension DeliveryViewController: DeliverUseCaseCollectionDelegate {\n    func useCaseCellSelected(_ index: Int) {\n        useCasesClicked(index)\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Optimization/OptimizationViewController.swift",
    "content": "//\n//  OptimizationViewController.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 18/09/2023.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\n\nclass OptimizationViewController: UIViewController {\n    @IBOutlet weak var vwBack: UIView!\n    @IBOutlet weak var lbOriginal: UILabel!\n    @IBOutlet weak var lbOptimized: UILabel!\n    @IBOutlet weak var ivOriginal: CLDUIImageView!\n    @IBOutlet weak var ivOptimized: CLDUIImageView!\n\n    @IBOutlet weak var lbOriginalFormat: UILabel!\n    @IBOutlet weak var lbOriginalDimensions: UILabel!\n    @IBOutlet weak var lbOriginalSize: UILabel!\n\n    @IBOutlet weak var lbOptimizedFormat: UILabel!\n    @IBOutlet weak var lbOptimizedDimensions: UILabel!\n    @IBOutlet weak var lbOptimizedSize: UILabel!\n\n    var type: OptimizationViewType = .Optimization\n\n    var publicId: String = \"Demo%20app%20content/optimization_optimized\"\n\n    var cloudinary = CloudinaryHelper.shared.cloudinary\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setOriginalImageView()\n        setOptimizedImageView()\n        if type == .FetchUpload {\n            EventsHandler.shared.logEvent(event: EventObject(name: \"Fetch\"))\n        } else {\n            EventsHandler.shared.logEvent(event: EventObject(name: \"Transform\"))\n        }\n    }\n\n    override func viewDidAppear(_ animated: Bool) {\n        super.viewDidAppear(animated)\n        loadImageData()\n    }\n\n    func setBackButton() {\n        let gesture = UITapGestureRecognizer(target: self, action: #selector(stepBack))\n        vwBack.addGestureRecognizer(gesture)\n    }\n\n    func setOriginalImageView() {\n        var url = cloudinary.createUrl().generate(publicId)\n        if type == .FetchUpload {\n\n            url = cloudinary.createUrl().setType(\"fetch\").generate(publicId)\n        }\n        let view = UIView()\n        \n        ivOriginal.cldSetImage(url!, cloudinary: cloudinary)\n\n        lbOriginalFormat.isHidden = true\n        lbOriginalDimensions.isHidden = true\n        lbOriginalSize.isHidden = true\n\n    }\n\n    func setOptimizedImageView() {\n        var url = cloudinary.createUrl().setTransformation(CLDTransformation().setQuality(\"auto\").setFetchFormat(\"heic\").setDpr(\"auto\").setWidth(0.4).setCrop(\"scale\")).generate(publicId)\n        if type == .FetchUpload {\n\n            url = cloudinary.createUrl().setType(\"fetch\").setTransformation(CLDTransformation().setQuality(\"auto\").setFetchFormat(\"auto\").setDpr(\"auto\").setWidth(0.7).setCrop(\"scale\")).generate(publicId)\n        }\n        ivOptimized.cldSetImage(url!, cloudinary: cloudinary)\n\n        lbOptimizedFormat.isHidden = true\n        lbOptimizedDimensions.isHidden = true\n        lbOptimizedSize.isHidden = true\n    }\n\n    @objc func loadImageData() {\n        var originalUrl = cloudinary.createUrl().generate(publicId)!\n        if type == .FetchUpload {\n            originalUrl = cloudinary.createUrl().setType(\"fetch\").generate(publicId)!\n        }\n        FileUtils.getImageInfo(URL(string: originalUrl)!) { format,size, dimensions  in\n            self.lbOriginalFormat.text = \"\\(format.uppercased()) ⏺\"\n            self.lbOriginalDimensions.text = \"\\(Int(dimensions.width))x\\(Int(dimensions.height)) ⏺\"\n            self.lbOriginalSize.text = \"\\(size)MB\"\n\n            self.lbOriginalFormat.isHidden = false\n            self.lbOriginalDimensions.isHidden = false\n            self.lbOriginalSize.isHidden = false\n        }\n        var optimizedUrl = cloudinary.createUrl().setTransformation(CLDTransformation().setQuality(\"auto\").setFetchFormat(\"auto\").setDpr(\"auto\").setWidth(0.4).setCrop(\"scale\")).generate(publicId)!\n        if type == .FetchUpload {\n            optimizedUrl = cloudinary.createUrl().setType(\"fetch\").setTransformation(CLDTransformation().setQuality(\"auto\").setFetchFormat(\"auto\").setDpr(\"auto\").setWidth(0.7).setCrop(\"scale\")).generate(publicId)!\n        }\n        FileUtils.getImageInfo(URL(string: optimizedUrl)!) { format, size, dimensions in\n            self.lbOptimizedFormat.text = \"\\(format.uppercased()) ⏺\"\n            self.lbOptimizedDimensions.text = \"\\(Int(dimensions.width))x\\(Int(dimensions.height)) ⏺\"\n            self.lbOptimizedSize.text = \"\\(size)MB\"\n\n            self.lbOptimizedFormat.isHidden = false\n            self.lbOptimizedDimensions.isHidden = false\n            self.lbOptimizedSize.isHidden = false\n        }\n    }\n\n    @objc func stepBack() {\n        self.dismiss(animated: true)\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Transformation/DeliveryTransformCollectionController.swift",
    "content": "//\n//  DeliveryTransformCollectionController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 30/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nprotocol DeliveryTransformCollectionDelegate {\n    func transformCellSelected(_ index: Int)\n}\n\nclass DeliveryTransformCollectionController: NSObject,  UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {\n\n    var delegate: DeliveryTransformCollectionDelegate\n\n    init(_ delegate: DeliveryTransformCollectionDelegate) {\n        self.delegate = delegate\n    }\n\n    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {\n        return 4\n    }\n\n    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {\n        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: \"transfromationCell\", for: indexPath) as! TransformationCell\n        cell.setCellContent(indexPath.row)\n        return cell\n    }\n\n    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {\n        return CGSize(width: 224, height: 135)\n    }\n\n    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {\n        delegate.transformCellSelected(indexPath.row)\n    }\n\n\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Transformation/Reveal Image/RevealImageController.swift",
    "content": "//\n//  RevealImageController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 30/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass RevealImageController: UIViewController {\n\n    @IBOutlet weak var ivMain: RevealImageView!\n\n    func setMainImageView(rightImage: String?, leftImage: String?) {\n        ImageHelper.getImageFromURL(URL(string: rightImage!)!) { image in\n            DispatchQueue.main.async {\n                self.ivMain.rightImage = image\n            }\n        }\n        ImageHelper.getImageFromURL(URL(string: leftImage!)!) { image in\n            DispatchQueue.main.async {\n                self.ivMain.leftImage = image\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Transformation/Smart Cropping/SmartCroppingController.swift",
    "content": "//\n//  SmartCroppingController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 30/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass SmartCroppingController: UIViewController {\n    \n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Transformation/TransformCollectionCell.swift",
    "content": "//\n//  TransformCollectionCell.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 08/01/2024.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\nclass TransformCollectionCell: UICollectionViewCell {\n\n    @IBOutlet weak var lbMain: UILabel!\n    @IBOutlet weak var ivMain: CLDUIImageView!\n\n    func setCellBy(index: Int) {\n        switch index {\n        case 0:\n            ivMain.cldSetImage(publicId: \"Demo%20app%20content/content-aware-crop-4-ski_louxkt\", cloudinary: CloudinaryHelper.shared.cloudinary, transformation: CLDTransformation().setCrop(\"thumb\"))\n            lbMain.text = \"Smart Cropping\"\n        case 1:\n            ivMain.cldSetImage(publicId: \"Demo%20app%20content/layers-fashion-2_1_xsfbvm\", cloudinary: CloudinaryHelper.shared.cloudinary, transformation: CLDTransformation().setCrop(\"thumb\"))\n            lbMain.text = \"Localization & branding\"\n        case 2:\n            ivMain.cldSetImage(publicId: \"Demo%20app%20content/bgr-furniture-1_isnptj\", cloudinary: CloudinaryHelper.shared.cloudinary, transformation: CLDTransformation().setCrop(\"thumb\"))\n            lbMain.text = \"Background normalizing\"\n        case 3:\n            ivMain.cldSetImage(publicId: \"Demo%20app%20content/recolor-tshirt-5_omapls\", cloudinary: CloudinaryHelper.shared.cloudinary, transformation: CLDTransformation().setCrop(\"thumb\"))\n            lbMain.text = \"Color Alternation\"\n        default:\n            break\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Transformation/TransformCollectionController.swift",
    "content": "//\n//  TransformCollectionController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 08/01/2024.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\n\nprotocol TransformCollectionDelegate {\n    func cellSelected(_ index: Int)\n}\n\nclass TransformCollectionController: NSObject, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {\n\n    var delegate: TransformCollectionDelegate\n\n    var selectedCellIndex = 0\n\n    init(_ delegate: TransformCollectionDelegate) {\n        self.delegate = delegate\n    }\n\n\n    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {\n        4\n    }\n\n    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {\n        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: \"TransformCollectionCell\", for: indexPath) as! TransformCollectionCell\n        cell.setCellBy(index: indexPath.row)\n        setSelectedCell(cell, index: indexPath.row)\n        return cell\n    }\n\n    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {\n         let previousSelectedIndexPath = selectedCellIndex\n         selectedCellIndex = indexPath.row\n         delegate.cellSelected(indexPath.row)\n         updateSelectedCellAppearance(collectionView, indexPath)\n         updateSelectedCellAppearance(collectionView, IndexPath(row: previousSelectedIndexPath, section: 0))\n     }\n\n     func updateSelectedCellAppearance(_ collectionView: UICollectionView, _ indexPath: IndexPath) {\n         if let cell = collectionView.cellForItem(at: indexPath) as? TransformCollectionCell {\n             setSelectedCell(cell, index: indexPath.row)\n         }\n     }\n\n    func setSelectedCell(_ cell: TransformCollectionCell, index: Int) {\n        if index == selectedCellIndex {\n            cell.isSelected = true\n            cell.layer.borderColor = UIColor(named: \"primary\")?.cgColor\n            cell.layer.borderWidth = 3\n            cell.layer.cornerRadius = 4\n        } else {\n            cell.layer.borderWidth = 0\n        }\n    }\n\n    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {\n        return CGSize(width: 84, height: 116)\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Transformation/TransformViewController.swift",
    "content": "//\n//  TransformViewController.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 12/09/2023.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\n\nclass TransformViewController: UIViewController {\n\n    @IBOutlet weak var cvMain: UICollectionView!\n    @IBOutlet weak var vwContainer: UIView!\n\n    var currentController: UIViewController!\n\n    var innerIndex: Int = 0\n\n    var collectionController: TransformCollectionController!\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setCollectionView()\n        setContainerView(innerIndexToType(innerIndex))\n        EventsHandler.shared.logEvent(event: EventObject(name: \"Inner Trasnform\"))\n    }\n\n    private func innerIndexToType(_ index: Int) -> TransformContainerType {\n        switch index {\n        case 0:\n            return .SmartCropping\n        case 1:\n            return .TextLayer\n        case 2:\n            return .BackgroundRemoval\n        case 3:\n            return .ReColor\n        default:\n            return .SmartCropping\n        }\n    }\n\n    private func setContainerView(_ type: TransformContainerType) {\n        removeCurrentController()\n        switch type {\n        case .SmartCropping:\n            currentController = UIStoryboard(name: \"SmartCropping\", bundle: nil).instantiateViewController(identifier: \"SmartCroppingController\")\n            currentController.view.frame = vwContainer.bounds\n            addChild(currentController)\n            vwContainer.addSubview(currentController.view)\n            currentController.didMove(toParent: self)\n            collectionController.selectedCellIndex = 0\n        case .TextLayer:\n            currentController = UIStoryboard(name: \"RevealImage\", bundle: nil).instantiateViewController(identifier: \"RevealImageController\")\n            currentController.view.frame = vwContainer.bounds\n            addChild(currentController)\n            vwContainer.addSubview(currentController.view)\n            currentController.didMove(toParent: self)\n            (currentController as! RevealImageController).setMainImageView(rightImage: CloudinaryHelper.shared.cloudinary.createUrl().generate(\"Demo%20app%20content/layers-fashion-2_1_xsfbvm\"), leftImage: CloudinaryHelper.shared.cloudinary.createUrl().setTransformation(CLDTransformation()\n                .setOverlay(\"text:Arial_72:NEW%2520COLLECTION\").setColor(\"white\").chain()\n                .setFlags(\"layer_apply\").setGravity(\"center\")).generate(\"Demo%20app%20content/layers-fashion-2_1_xsfbvm\"))\n            collectionController.selectedCellIndex = 1\n        case .BackgroundRemoval:\n            currentController = UIStoryboard(name: \"RevealImage\", bundle: nil).instantiateViewController(identifier: \"RevealImageController\") as! RevealImageController\n            currentController.view.frame = vwContainer.bounds\n            addChild(currentController)\n            vwContainer.addSubview(currentController.view)\n            currentController.didMove(toParent: self)\n            (currentController as! RevealImageController).setMainImageView(rightImage: CloudinaryHelper.shared.cloudinary.createUrl().generate(\"Demo%20app%20content/bgr-furniture-1_isnptj\"), leftImage: CloudinaryHelper.shared.cloudinary.createUrl().setTransformation(CLDTransformation().setEffect(\"background_removal\")).generate(\"Demo%20app%20content/bgr-furniture-1_isnptj\"))\n            collectionController.selectedCellIndex = 2\n        case .ReColor:\n            currentController = UIStoryboard(name: \"RevealImage\", bundle: nil).instantiateViewController(identifier: \"RevealImageController\") as! RevealImageController\n            currentController.view.frame = vwContainer.bounds\n            addChild(currentController)\n            vwContainer.addSubview(currentController.view)\n            currentController.didMove(toParent: self)\n            (currentController as! RevealImageController).setMainImageView(rightImage: CloudinaryHelper.shared.cloudinary.createUrl().generate(\"Demo%20app%20content/recolor-tshirt-5_omapls\"), leftImage: CloudinaryHelper.shared.cloudinary.createUrl().setTransformation(CLDTransformation().setEffect(\"gen_recolor:prompt_t-shirt;to-color_8fbc8f\")).generate(\"Demo%20app%20content/recolor-tshirt-5_omapls\"))\n            collectionController.selectedCellIndex = 3\n        }\n    }\n\n    private func setCollectionView() {\n        collectionController = TransformCollectionController(self)\n        cvMain.delegate = collectionController\n        cvMain.dataSource = collectionController\n\n        let flow = cvMain.collectionViewLayout as! UICollectionViewFlowLayout\n\n            let itemSpacing: CGFloat = 10\n            let itemsInOneLine: CGFloat = 10\n            flow.sectionInset = UIEdgeInsets(top: 10, left: 16, bottom: 0, right: 16)\n            let width = UIScreen.main.bounds.size.width - itemSpacing * CGFloat(itemsInOneLine - 1)\n            flow.itemSize = CGSize(width: floor(width/itemsInOneLine), height: width/itemsInOneLine)\n            flow.minimumInteritemSpacing = 10\n            flow.minimumLineSpacing = itemSpacing\n    }\n\n    private func removeCurrentController() {\n        currentController?.willMove(toParent: nil)\n        currentController?.view.removeFromSuperview()\n        currentController?.removeFromParent()\n    }\n}\nextension TransformViewController: TransformCollectionDelegate {\n    func cellSelected(_ index: Int) {\n        switch index {\n        case 0:\n            setContainerView(.SmartCropping)\n        case 1:\n            setContainerView(.TextLayer)\n        case 2:\n            setContainerView(.BackgroundRemoval)\n        case 3:\n            setContainerView(.ReColor)\n        default:\n            break\n        }\n    }\n}\n\n\nenum TransformContainerType {\n    case SmartCropping\n    case TextLayer\n    case BackgroundRemoval\n    case ReColor\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Transformation/TransformationCell.swift",
    "content": "//\n//  TransformationCell.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 30/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass TransformationCell: UICollectionViewCell {\n    @IBOutlet weak var ivMain: UIImageView!\n    @IBOutlet weak var lbMain: UILabel!\n    \n    func setCellContent(_ index: Int) {\n        switch index {\n        case 0:\n            ivMain.image = UIImage(named: \"smart_cropping\")\n            lbMain.text = \"Smart Cropping\"\n        case 1:\n            ivMain.image = UIImage(named: \"localization_branding\")\n            lbMain.text = \"Localization & Branding\"\n        case 2:\n            ivMain.image = UIImage(named: \"background_normalizing\")\n            lbMain.text = \"Background normalizing\"\n        case 3:\n            ivMain.image = UIImage(named: \"color_alternation\")\n            lbMain.text = \"Color alternation\"\n        default:\n            break\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Use Cases/DeliveryUseCasesCollectionController.swift",
    "content": "//\n//  DeliveryUseCasesCollectionController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 30/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nprotocol DeliverUseCaseCollectionDelegate {\n    func useCaseCellSelected(_ index: Int)\n}\n\nclass DeliveryUseCasesCollectionController: NSObject,  UICollectionViewDelegate, UICollectionViewDataSource {\n\n    var delegate: DeliverUseCaseCollectionDelegate\n\n    init(_ delegate: DeliverUseCaseCollectionDelegate) {\n        self.delegate = delegate\n    }\n\n    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {\n        return 4\n    }\n    \n    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {\n        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: \"useCaseCell\", for: indexPath) as! UseCaseCell\n        cell.setCellBy(index: indexPath.row)\n        return cell\n    }\n\n    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {\n        delegate.useCaseCellSelected(indexPath.row)\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Use Cases/Screens/ConditionalProductViewController.swift",
    "content": "//\n//  ConditionalProductViewController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 22/02/2024.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\n\nclass ConditionalProductViewController: UIViewController {\n\n    @IBOutlet weak var ivTopLeft: CLDUIImageView!\n    @IBOutlet weak var ivTopRight: CLDUIImageView!\n    @IBOutlet weak var ivBottom: CLDUIImageView!\n\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setImageViews()\n    }\n\n    private func setImageViews() {\n        ivTopLeft.cldSetImage(publicId: \"Group_15_jda5ms\", cloudinary: CloudinaryHelper.shared.cloudinary)\n\n        ivTopRight.cldSetImage(publicId: \"tshirt4_1_si0swc\", cloudinary: CloudinaryHelper.shared.cloudinary)\n\n        ivBottom.cldSetImage(publicId: \"tshirt4_1_si0swc\", cloudinary: CloudinaryHelper.shared.cloudinary, transformation: CLDTransformation().setOverlayWithLayer(CLDLayer().setPublicId(publicId: \"Group_15_jda5ms\")).setGravity(.northWest).setWidth(0.4).setX(10).setY(10))\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Use Cases/Screens/IntegrateAIViewController.swift",
    "content": "//\n//  IntegrateAIViewController.swift\n//  Cloudinary_Example\n//\n//  Created by Adi Mizrahi on 26/02/2024.\n//  Copyright © 2024 CocoaPods. All rights reserved.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\nimport AVKit\n\nclass IntegrateAIViewController: UIViewController {\n\n    @IBOutlet weak var vwVideoView: UIView!\n\n    var videoPublicId: String = \"\"\n    var player: CLDVideoPlayer!\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setVideoView()\n    }\n\n    private func setVideoView() {\n        player = CLDVideoPlayer(publicId: videoPublicId, cloudinary: CloudinaryHelper.shared.cloudinary)\n        let playerLayer = AVPlayerLayer(player: player)\n        playerLayer.frame = vwVideoView.bounds\n        playerLayer.videoGravity = .resizeAspectFill\n        vwVideoView.layer.addSublayer(playerLayer)\n\n        // Add observer for AVPlayerItemDidPlayToEndTime\n        NotificationCenter.default.addObserver(self,\n                                               selector: #selector(playerItemDidReachEnd),\n                                               name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,\n                                               object: player.currentItem)\n\n        player.play()\n    }\n\n    @objc private func playerItemDidReachEnd(notification: Notification) {\n        if let playerItem = notification.object as? AVPlayerItem {\n            // Seek to the start of the video to loop it\n            playerItem.seek(to: .zero)\n            player.play()\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Use Cases/Screens/NormalizingProductAssetsViewController.swift",
    "content": "//\n//  NormalizingProductAssetsViewController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 21/02/2024.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\n\nclass NormalizingProductAssetsViewController: UIViewController {\n    \n    @IBOutlet weak var ivTopLeft: CLDUIImageView!\n    @IBOutlet weak var ivTopRight: CLDUIImageView!\n    @IBOutlet weak var ivMidRight: CLDUIImageView!\n    @IBOutlet weak var ivBottomLeft: CLDUIImageView!\n    @IBOutlet weak var ivBottomMid: CLDUIImageView!\n    @IBOutlet weak var ivBottomRight: CLDUIImageView!\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setImageViews()\n    }\n\n    private func setImageViews() {\n        ivTopLeft.cldSetImage(publicId: \"pexels-aditya-aiyar-1407354_tiw4bv\", cloudinary: CloudinaryHelper.shared.cloudinary)\n        ivTopRight.cldSetImage(publicId: \"pexels-mnz-1670766_n9hfoi\", cloudinary: CloudinaryHelper.shared.cloudinary)\n        ivMidRight.cldSetImage(publicId: \"pexels-wendy-wei-12511453_b4shho\", cloudinary: CloudinaryHelper.shared.cloudinary)\n        ivBottomLeft.cldSetImage(publicId: \"Rectangle_1434_fcnobi\", cloudinary: CloudinaryHelper.shared.cloudinary)\n        ivBottomMid.cldSetImage(publicId: \"Rectangle_1435_mwtszu\", cloudinary: CloudinaryHelper.shared.cloudinary)\n        ivBottomRight.cldSetImage(publicId: \"Rectangle_1436_kdsfld\", cloudinary: CloudinaryHelper.shared.cloudinary)\n\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Use Cases/UseCaseCell.swift",
    "content": "//\n//  UseCaseCell.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 30/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass UseCaseCell: UICollectionViewCell {\n\n    @IBOutlet weak var lbMain: UILabel!\n    @IBOutlet weak var vwGradient: GradientView!\n\n    func setCellBy(index: Int) {\n        switch index {\n        case 0:\n            lbMain.text = \"Normalizing Product Assets - Sizing\"\n        case 1:\n            lbMain.text = \"Conditional Product Badging\"\n        case 2:\n            lbMain.text = \"Adapt video to any screen\"\n        case 3:\n            lbMain.text = \"Integrate AI-generated backgrounds\"\n        default:\n            break\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Use Cases/UseCaseCollectionCell.swift",
    "content": "//\n//  UseCaseCollectionCell.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 21/02/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass UseCaseCollectionCell: UICollectionViewCell {\n    @IBOutlet weak var lbMain: UILabel!\n\n    func setCellBy(index: Int) {\n        switch index {\n        case 0:\n            lbMain.text = \"Normalizing Product Assets - Sizing\"\n        case 1:\n            lbMain.text = \"Conditional Product Badging\"\n        case 2:\n            lbMain.text = \"Adapt video to any screen\"\n        case 3:\n            lbMain.text = \"Integrate AI-generated backgrounds\"\n        default:\n            break\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Use Cases/UseCasesCollectionController.swift",
    "content": "//\n//  UseCasesCollectionController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 21/02/2024.\n//\n\nimport Foundation\nimport UIKit\n\nprotocol UseCasesCollectionDelegate {\n    func cellSelected(_ index: Int)\n}\n\nclass UseCasesCollectionController: NSObject,  UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {\n\n    var delegate: UseCasesCollectionDelegate\n\n    var selectedCellIndex = 0\n\n    init(_ delegate: UseCasesCollectionDelegate) {\n        self.delegate = delegate\n    }\n\n    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {\n        4\n    }\n\n    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {\n        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: \"UseCaseCollectionCell\", for: indexPath) as! UseCaseCollectionCell\n        cell.setCellBy(index: indexPath.row)\n        setSelectedCell(cell, index: indexPath.row)\n        return cell\n    }\n\n    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {\n        selectedCellIndex = indexPath.row\n        delegate.cellSelected(indexPath.row)\n        collectionView.reloadData()\n    }\n\n    private func setSelectedCell(_ cell: UseCaseCollectionCell, index: Int) {\n        if index == selectedCellIndex {\n            cell.isSelected = true\n            cell.layer.borderColor = UIColor(named: \"primary\")?.cgColor\n            cell.layer.borderWidth = 3\n            cell.layer.cornerRadius = 4\n        } else {\n            cell.layer.borderWidth = 0\n        }\n    }\n\n    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {\n        return CGSize(width: 80, height: 116)\n    }\n\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Transform/Use Cases/UseCasesViewController.swift",
    "content": "//\n//  UseCasesViewController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 21/02/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass UseCasesViewController: UIViewController {\n\n    @IBOutlet weak var vwContainer: UIView!\n    @IBOutlet weak var cvMain: UICollectionView!\n\n    var innerIndex: Int = 0\n\n    var currentController: UIViewController!\n\n    var collectionController: UseCasesCollectionController!\n\n    override func viewDidAppear(_ animated: Bool) {\n        super.viewDidAppear(animated)\n        setCollectionView()\n        setContainerView(innerIndexToType(innerIndex))\n        EventsHandler.shared.logEvent(event: EventObject(name: \"Use Cases\"))\n    }\n\n    private func innerIndexToType(_ index: Int) -> UseCaseContainerType {\n        switch index {\n        case 0:\n            return .NormalizingProductAssets\n        case 1:\n            return .ConditionalProduct\n        case 2:\n            return .AdaptVideo\n        case 3:\n            return .IntegrateAI\n        default:\n            return .NormalizingProductAssets\n        }\n    }\n\n    private func setCollectionView() {\n        collectionController = UseCasesCollectionController(self)\n        cvMain.delegate = collectionController\n        cvMain.dataSource = collectionController\n\n        let flow = cvMain.collectionViewLayout as! UICollectionViewFlowLayout\n\n            let itemSpacing: CGFloat = 10\n            let itemsInOneLine: CGFloat = 10\n            flow.sectionInset = UIEdgeInsets(top: 10, left: 12, bottom: 0, right: 16)\n            let width = UIScreen.main.bounds.size.width - itemSpacing * CGFloat(itemsInOneLine - 1)\n            flow.itemSize = CGSize(width: floor(width/itemsInOneLine), height: width/itemsInOneLine)\n            flow.minimumInteritemSpacing = 10\n            flow.minimumLineSpacing = itemSpacing\n    }\n\n    private func setContainerView(_ type: UseCaseContainerType) {\n        removeCurrentController()\n        switch type {\n        case .NormalizingProductAssets:\n            currentController = UIStoryboard(name: \"NormalizingProductAssets\", bundle: nil).instantiateViewController(identifier: \"NormalizingProductAssetsViewController\")\n            currentController.view.frame = vwContainer.bounds\n            addChild(currentController)\n            vwContainer.addSubview(currentController.view)\n            currentController.didMove(toParent: self)\n            collectionController.selectedCellIndex = 0\n        case .ConditionalProduct:\n            currentController = UIStoryboard(name: \"ConditionalProduct\", bundle: nil).instantiateViewController(identifier: \"ConditionalProductViewController\")\n            currentController.view.frame = vwContainer.bounds\n            addChild(currentController)\n            vwContainer.addSubview(currentController.view)\n            currentController.didMove(toParent: self)\n            collectionController.selectedCellIndex = 1\n            break\n        case .AdaptVideo:\n            currentController = UIStoryboard(name: \"IntegrateAI\", bundle: nil).instantiateViewController(identifier: \"IntegrateAIViewController\")\n            (currentController as! IntegrateAIViewController).videoPublicId = \"DevApp_Adapt_Video_02_diett8\"\n            currentController.view.frame = vwContainer.bounds\n            addChild(currentController)\n            vwContainer.addSubview(currentController.view)\n            currentController.didMove(toParent: self)\n            collectionController.selectedCellIndex = 2\n        case .IntegrateAI:\n            currentController = UIStoryboard(name: \"IntegrateAI\", bundle: nil).instantiateViewController(identifier: \"IntegrateAIViewController\")\n            (currentController as! IntegrateAIViewController).videoPublicId = \"DevApp_Generative_Fill_01_fneqxw\"\n            currentController.view.frame = vwContainer.bounds\n            addChild(currentController)\n            vwContainer.addSubview(currentController.view)\n            currentController.didMove(toParent: self)\n            collectionController.selectedCellIndex = 3\n        }\n    }\n\n    private func removeCurrentController() {\n        currentController?.willMove(toParent: nil)\n        currentController?.view.removeFromSuperview()\n        currentController?.removeFromParent()\n    }\n}\nextension UseCasesViewController: UseCasesCollectionDelegate {\n    func cellSelected(_ index: Int) {\n        switch index {\n        case 0:\n            setContainerView(.NormalizingProductAssets)\n        case 1:\n            setContainerView(.ConditionalProduct)\n        case 2:\n            setContainerView(.AdaptVideo)\n        case 3:\n            setContainerView(.IntegrateAI)\n        default:\n            break\n        }\n    }\n}\n\nenum UseCaseContainerType {\n    case NormalizingProductAssets\n    case ConditionalProduct\n    case AdaptVideo\n    case IntegrateAI\n\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Upload/InnerUploadFrame.swift",
    "content": "//\n//  InnerUploadFrame.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 28/12/2023.\n//\n\nimport Foundation\nimport UIKit\n\nclass InnerUploadFrame: UIView {\n\n    @IBOutlet weak var lbTitle: UILabel!\n    @IBOutlet weak var lbSubtitle: UILabel!\n    @IBOutlet weak var vwGradientView: GradientView!\n\n    override init(frame: CGRect) {\n        super.init(frame: frame)\n        commonInit()\n    }\n\n    required init?(coder: NSCoder) {\n        super.init(coder: coder)\n        commonInit()\n    }\n\n    private func commonInit() {\n        let nibName = String(describing: type(of: self))\n        if let view = Bundle.main.loadNibNamed(nibName, owner: self, options: nil)?.first as? UIView {\n            view.frame = bounds\n            addSubview(view)\n        }\n        vwGradientView.layer.cornerRadius = vwGradientView.frame.height / 2\n    }\n\n    func setTitle(title: String) {\n        lbTitle.text = title\n    }\n\n    func setSubtitle(subtitle: String) {\n        lbSubtitle.text = subtitle\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Upload/Single Upload/SingleUploadCell.swift",
    "content": "//\n//  SingleUploadCell.swift\n//  Cloudinary_Example\n//\n//  Created by Adi Mizrahi on 18/07/2024.\n//  Copyright © 2024 CocoaPods. All rights reserved.\n//\n\n\nimport Foundation\nimport UIKit\nimport Cloudinary\nclass SingleUploadCell: UICollectionViewCell {\n    @IBOutlet weak var ivMain: CLDUIImageView!\n    \n    func setImage(_ url: String, _ cloudinary: CLDCloudinary) {\n        var urlString = url\n        if urlString.contains(\"video\") {\n            urlString = replaceExtension(urlString: urlString) ?? \"\"\n            ivMain.cldSetImage(urlString, cloudinary: cloudinary)\n            return\n        }\n        guard let url = URL(string: urlString) else {\n            return\n        }\n        let publicId = url.lastPathComponent\n        ivMain.cldSetImage(publicId: publicId, cloudinary: cloudinary, transformation: CLDTransformation().setCrop(\"thumb\"))\n    }\n\n    func replaceExtension(urlString: String) -> String? {\n        guard let url = URL(string: urlString) else {\n            return nil // Invalid URL\n        }\n        \n        // Get the last path component\n        let lastComponent = url.lastPathComponent\n\n        // Get the path extension\n        let pathExtension = (lastComponent as NSString).pathExtension\n\n        // Replace the path extension with \".jpg\"\n        let newLastPathComponent = (lastComponent as NSString).deletingPathExtension + \".jpg\"\n\n        // Create a new URL instance with the updated path component\n        if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) {\n            urlComponents.path = urlComponents.path.replacingOccurrences(of: lastComponent, with: newLastPathComponent)\n\n            // Get the updated URL string\n            if let updatedURLString = urlComponents.string {\n                return updatedURLString\n            }\n        }\n        \n        return urlString // Return original URL if there's any failure in updating the URL string\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Upload/Single Upload/SingleUploadCollectionController.swift",
    "content": "//\n//  SingleUploadCollectionController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 12/05/2024.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\n\nprotocol SingleUploadCollectionDelegate {\n    func presentController(_ controller: UIViewController)\n}\n\nclass SingleUploadCollectionController: NSObject, UICollectionViewDelegate, UICollectionViewDataSource {\n\n    var delegate: SingleUploadCollectionDelegate\n\n    var data: [AssetItems]\n    let cloudinary = CLDCloudinary(configuration: CLDConfiguration(cloudName: CloudinaryHelper.shared.getUploadCloud()!, secure: true))\n    weak var collectionView: UICollectionView? // Weak reference to collection view\n\n    init(delegate: SingleUploadCollectionDelegate, collectionView: UICollectionView) {\n        self.collectionView = collectionView\n        self.data = CoreDataHelper.shared.fetchData() ?? []\n        self.delegate = delegate\n        super.init()\n        collectionView.delegate = self\n        collectionView.dataSource = self\n    }\n\n    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {\n        return data.count\n    }\n\n    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {\n        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: \"uploadCell\", for: indexPath) as! SingleUploadCell\n        cell.setImage(data[indexPath.row].url, cloudinary)\n        return cell\n    }\n\n    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {\n        let controller = UIStoryboard(name: \"SingleUploadPreview\", bundle: nil).instantiateViewController(withIdentifier: \"SingleUploadPreview\") as! SingleUploadPreview\n        controller.url = data[indexPath.row].url\n        delegate.presentController(controller)\n    }\n\n    func refreshData() {\n        let newData = CoreDataHelper.shared.fetchData() ?? []\n        let oldData = data\n        data = newData // Update data\n\n        // Compute changes\n        var insertions: [IndexPath] = []\n        var deletions: [IndexPath] = []\n        var moves: [(from: IndexPath, to: IndexPath)] = []\n\n        // Find insertions and deletions\n        for (index, newItem) in newData.enumerated() {\n            if let oldIndex = oldData.firstIndex(where: { $0.id == newItem.id }) {\n                if index != oldIndex {\n                    moves.append((from: IndexPath(item: oldIndex, section: 0), to: IndexPath(item: index, section: 0)))\n                }\n            } else {\n                insertions.append(IndexPath(item: index, section: 0))\n            }\n        }\n\n        for (index, oldItem) in oldData.enumerated() {\n            if !newData.contains(where: { $0.id == oldItem.id }) {\n                deletions.append(IndexPath(item: index, section: 0))\n            }\n        }\n\n        // Apply changes to collection view\n        collectionView?.performBatchUpdates({\n            if !insertions.isEmpty {\n                collectionView?.insertItems(at: insertions)\n            }\n            if !deletions.isEmpty {\n                collectionView?.deleteItems(at: deletions)\n            }\n            for move in moves {\n                collectionView?.moveItem(at: move.from, to: move.to)\n            }\n        }, completion: nil)\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Upload/Single Upload/SingleUploadCollectionLayout.swift",
    "content": "//\n//  SingleUploadCollectionLayout.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 12/05/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass SingleUploadCollectionLayout: UICollectionViewFlowLayout {\n\n    var singleItemAttributes: UICollectionViewLayoutAttributes?\n\n    override func prepare() {\n        super.prepare()\n\n        guard let collectionView = collectionView else { return }\n\n        // Calculate item size to occupy one-third of the collection view's width\n        let itemWidth = (collectionView.bounds.width - minimumInteritemSpacing * 2 - minimumLineSpacing * 2) / 3\n        itemSize = CGSize(width: itemWidth, height: itemWidth)\n\n        // Calculate horizontal inset to center items\n        let inset = (collectionView.bounds.width - CGFloat(3) * itemWidth - minimumInteritemSpacing * 2) / 2\n\n        // Set section inset\n        sectionInset = UIEdgeInsets(top: sectionInset.top, left: inset, bottom: sectionInset.bottom, right: inset)\n\n        // Adjust alignment for single item\n        if collectionView.numberOfItems(inSection: 0) == 1 {\n            let indexPath = IndexPath(item: 0, section: 0)\n            singleItemAttributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)\n            singleItemAttributes?.frame.origin = CGPoint(x: sectionInset.left, y: sectionInset.top)\n        } else {\n            singleItemAttributes = nil\n        }\n    }\n\n    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {\n        if let singleItemAttributes = singleItemAttributes {\n            return [singleItemAttributes]\n        } else {\n            return super.layoutAttributesForElements(in: rect)\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Upload/Single Upload/SingleUploadPreview.swift",
    "content": "//\n//  SingleUploadPreview.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 12/05/2024.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\nimport AVKit\n\nclass SingleUploadPreview: UIViewController {\n\n    var url: String!\n    var cloudinary = CLDCloudinary(configuration: CLDConfiguration(cloudName: CloudinaryHelper.shared.getUploadCloud()!))\n\n    @IBOutlet weak var vwShare: UIView!\n    @IBOutlet weak var vwImage: UIView!\n    @IBOutlet weak var ivMain: CLDUIImageView!\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setShareView()\n        if url.contains(\"video\") {\n                        let player = CLDVideoPlayer(url: url)\n                            let playerController = AVPlayerViewController()\n\n                            playerController.player = player\n                            addChild(playerController)\n                            playerController.videoGravity = .resizeAspect\n                            vwImage.addSubview(playerController.view)\n                            playerController.view.frame = vwImage.bounds\n                            playerController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]\n                            playerController.didMove(toParent: self)\n                            player.play()\n        } else {\n            ivMain.cldSetImage(url, cloudinary: cloudinary)\n        }\n    }\n\n    private func setShareView() {\n        let gesture = UITapGestureRecognizer(target: self, action: #selector(share))\n        vwShare.addGestureRecognizer(gesture)\n    }\n\n    @objc private func share() {\n        // Check if the image is available\n        if let image = ivMain.image {\n            // If image is available, share the image\n            let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil)\n\n            // Present the activity view controller\n            let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first\n            if let viewController = window!.rootViewController {\n                activityViewController.popoverPresentationController?.sourceView = viewController.view\n                self.present(activityViewController, animated: true, completion: nil)\n            }\n        } else {\n            // If image is not available, share the URL\n            guard let url = self.url else {\n                return\n            }\n\n            let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)\n\n            // Present the activity view controller\n            let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first\n            if let viewController = window!.rootViewController {\n                activityViewController.popoverPresentationController?.sourceView = viewController.view\n                self.present(activityViewController, animated: true, completion: nil)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Upload/Single Upload/SingleUploadViewController.swift",
    "content": "//\n//  SingleUploadViewController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 11/01/2024.\n//\n\nimport Foundation\nimport UIKit\nimport Photos\nimport Cloudinary\nimport AVKit\n\nclass SingleUploadViewController: UIViewController {\n\n    @IBOutlet weak var vwImage: UIView!\n    @IBOutlet weak var vwOpenGallery: UIView!\n    @IBOutlet weak var lbButton: UILabel!\n    @IBOutlet weak var cvMain: UICollectionView!\n\n    weak var delegate: UploadChoiceControllerDelegate!\n\n    var uploadWidget: CLDUploaderWidget!\n\n    var collectionController: SingleUploadCollectionController!\n    var collectionLayout: SingleUploadCollectionLayout!\n\n    var url: String?\n\n    var cloudinary = CLDCloudinary(configuration: CLDConfiguration(cloudName: CloudinaryHelper.shared.getUploadCloud()!))\n\n    var uploadLoadingView: UploadLoadingView?\n\n    var type: UploadViewType = .Upload\n\n    private var imagePicker: UIImagePickerController!\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setOpenGalleryView()\n        setMainCollectionView()\n        switch type {\n        case .Upload:\n            EventsHandler.shared.logEvent(event: EventObject(name: \"Upload\"))\n        case .UploadLarge:\n            EventsHandler.shared.logEvent(event: EventObject(name: \"Upload Large\"))\n        case .UploadWidget:\n            EventsHandler.shared.logEvent(event: EventObject(name: \"Upload Widget\"))\n        }\n    }\n\n    private func setMainCollectionView() {\n        collectionController = SingleUploadCollectionController(delegate: self, collectionView: cvMain)\n        collectionLayout = SingleUploadCollectionLayout()\n        cvMain.delegate = collectionController\n        cvMain.dataSource = collectionController\n        cvMain.collectionViewLayout = collectionLayout\n    }\n\n    private func setOpenGalleryView() {\n        vwOpenGallery.layer.cornerRadius = vwOpenGallery.frame.height / 2\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(openGalleryClicked))\n        vwOpenGallery.addGestureRecognizer(tapGesture)\n    }\n\n    @objc private func openGalleryClicked() {\n        if type == .UploadWidget {\n\n        } else {\n            if imagePicker == nil {\n                imagePicker = UIImagePickerController()\n            }\n            if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum){\n                imagePicker.delegate = self\n                if type == .UploadLarge {\n                    imagePicker.mediaTypes = [\"public.movie\"]\n                }\n                imagePicker.sourceType = .photoLibrary\n                imagePicker.allowsEditing = false\n                present(imagePicker, animated: true, completion: nil)\n            }\n        }\n    }\n\n    private func addUploadingView() {\n        let loadingViewSize = CGSize(width: 180, height: 110)\n        let loadingViewOrigin = CGPoint(x: (vwImage.frame.width - loadingViewSize.width) / 2, y: (vwImage.frame.height - loadingViewSize.height) / 2)\n\n        uploadLoadingView = UploadLoadingView(frame: CGRect(origin: loadingViewOrigin, size: loadingViewSize))\n        uploadLoadingView!.startAnimation()\n        vwImage.addSubview(uploadLoadingView!)\n    }\n\n    private func removeUploadingView() {\n        if let uploadLoadingView = uploadLoadingView {\n            AnimationHelper.animateOut(view: uploadLoadingView)\n        }\n    }\n\n    func uploadImage(_ image: UIImage) {\n        addUploadingView()\n        let data = image.pngData()\n        cloudinary.createUploader().upload(data: data!, uploadPreset: \"ios_sample\", completionHandler:  { response, error in\n            if let response = response {\n                CoreDataHelper.shared.insertData(AssetModel(deliveryType: response.type ?? \"upload\", assetType: response.resourceType ?? \"image\", transformation: \"\", publicId: response.publicId ?? \"\", url: response.secureUrl ?? \"\"))\n            }\n            DispatchQueue.main.async {\n                UIView.animate(withDuration: 0.3) {\n                    self.collectionController.refreshData()\n                    self.cvMain.reloadData()\n                }\n                self.removeUploadingView()\n            }\n        })\n    }\n\n    func uploadVideo(_ url: URL) {\n        addUploadingView()\n        let params = CLDUploadRequestParams()\n        params.setResourceType(\"video\")\n        cloudinary.createUploader().upload(url: url as URL, uploadPreset: \"ios_sample\", params: params, completionHandler:  { response, error in\n            if let response = response {\n                CoreDataHelper.shared.insertData(AssetModel(deliveryType: response.type ?? \"upload\", assetType: response.resourceType ?? \"video\", transformation: \"\", publicId: response.publicId ?? \"\", url: response.secureUrl ?? \"\"))\n            }\n            DispatchQueue.main.async {\n                UIView.animate(withDuration: 0.3) {\n                    self.collectionController.refreshData()\n                    self.cvMain.reloadData()\n                }\n                self.removeUploadingView()\n            }\n        })\n    }\n}\n\nextension SingleUploadViewController:  UINavigationControllerDelegate, UIImagePickerControllerDelegate {\n    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {\n        picker.dismiss(animated: true, completion: nil)\n        if let image = info[.originalImage] as? UIImage {\n            uploadImage(image)\n        }\n        if let url = info[.mediaURL] as? URL {\n            uploadVideo(url)\n        }\n    }\n}\nextension SingleUploadViewController: CLDUploaderWidgetDelegate {\n    func uploadWidget(_ widget: CLDUploaderWidget, willCall uploadRequests: [CLDUploadRequest]) {\n        addUploadingView()\n      uploadRequests[0].response( { response, error in\n          self.cvMain.reloadData()\n          self.removeUploadingView()\n      } )\n    }\n    func widgetDidCancel(_ widget: CLDUploaderWidget) {\n    }\n    func uploadWidgetDidDismiss() {\n    }\n}\n\nextension SingleUploadViewController: SingleUploadCollectionDelegate {\n    func presentController(_ controller: UIViewController) {\n        self.present(controller, animated: true)\n    }\n\n\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Upload/Upload Does Not Exist/UploadDoesNotExistController.swift",
    "content": "//\n//  UploadDoesNotExistController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 30/01/2024.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\n\nclass UploadDoesNotExistController: UIViewController {\n    @IBOutlet weak var vwUploadContainer: UIView!\n    @IBOutlet weak var vwUpload: UIView!\n    @IBOutlet weak var aiLoading: UIActivityIndicatorView!\n    @IBOutlet weak var lbUploadButton: UILabel!\n    @IBOutlet weak var lbUploadContainer: UILabel!\n\n    private var imagePicker: UIImagePickerController!\n    weak var delegate: UploadChoiceControllerDelegate!\n\n    var uploadWidget: CLDUploaderWidget!\n\n    var type: UploadViewType = .Upload\n\n    var cloudinary = CLDCloudinary(configuration: CLDConfiguration(cloudName: CloudinaryHelper.shared.getUploadCloud()!))\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        switch type {\n        case .Upload:\n            EventsHandler.shared.logEvent(event: EventObject(name: \"Upload\"))\n        case .UploadLarge:\n            lbUploadButton.text = \"Upload Video\"\n            lbUploadContainer.text = \"Upload your video now and let the magic begin!\"\n            EventsHandler.shared.logEvent(event: EventObject(name: \"Upload Large\"))\n        case .UploadWidget:\n            EventsHandler.shared.logEvent(event: EventObject(name: \"Upload Widget\"))\n        }\n    }\n\n    override func viewDidAppear(_ animated: Bool) {\n        super.viewDidAppear(animated)\n        setUploadImageView()\n    }\n\n    func setUploadImageView() {\n        vwUpload.layer.cornerRadius = vwUpload.frame.height / 2\n\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(uploadClicked))\n        vwUpload.addGestureRecognizer(tapGesture)\n    }\n\n    @objc private func uploadClicked() {\n        if type == .UploadWidget {\n            openUploadWidget()\n        } else {\n            if imagePicker == nil {\n                imagePicker = UIImagePickerController()\n            }\n            if UIImagePickerController.isSourceTypeAvailable(.savedPhotosAlbum){\n                if type == .UploadLarge {\n                    imagePicker.mediaTypes = [\"public.movie\"]\n                }\n                imagePicker.delegate = self\n                imagePicker.sourceType = .photoLibrary\n                imagePicker.allowsEditing = false\n                present(imagePicker, animated: true, completion: nil)\n            }\n        }\n    }\n\n    private func openUploadWidget() {\n        let configuration = CLDWidgetConfiguration(\n          uploadType: CLDUploadType(signed: false, preset: \"ios_sample\"))\n\n        uploadWidget = CLDUploaderWidget(\n          cloudinary: cloudinary,\n          configuration: configuration,\n          images: nil,\n          delegate: self)\n\n        uploadWidget.presentWidget(from: self)\n    }\n\n    private func showUploadingView() {\n            vwUploadContainer.isHidden = true\n            aiLoading.isHidden = false\n    }\n\n    private func hideUploadingView() {\n        self.aiLoading.isHidden = true\n    }\n\n    func uploadImage(_ image: UIImage) {\n        showUploadingView()\n        let data = image.pngData()\n        cloudinary.createUploader().upload(data: data!, uploadPreset: \"ios_sample\", completionHandler:  { response, error in\n                    guard let response = response else {\n                        return\n                    }\n                    CoreDataHelper.shared.insertData(AssetModel(deliveryType: response.type ?? \"upload\", assetType: response.resourceType ?? \"image\", transformation: \"\", publicId: response.publicId ?? \"\", url: response.secureUrl ?? \"\"))\n\n                    DispatchQueue.main.async {\n                        self.delegate.switchToController(.UploadExist, url: response.secureUrl)\n                        self.hideUploadingView()\n                    }\n                })\n    }\n\n    func uploadVideo(_ url: NSURL) {\n        showUploadingView()\n        let params = CLDUploadRequestParams()\n        params.setResourceType(\"video\")\n        cloudinary.createUploader().upload(url: url as URL, uploadPreset: \"ios_sample\", params: params, completionHandler:  { response, error in\n            DispatchQueue.main.async {\n                self.delegate.switchToController(.UploadExist, url: response?.secureUrl)\n                self.hideUploadingView()\n            }\n        })\n    }\n}\n\nextension UploadDoesNotExistController:  UINavigationControllerDelegate, UIImagePickerControllerDelegate {\n    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {\n        picker.dismiss(animated: true, completion: nil)\n        if let image = info[.originalImage] as? UIImage {\n            uploadImage(image)\n       }\n        if let url = info[.mediaURL] as? NSURL {\n            uploadVideo(url)\n        }\n    }\n}\nextension UploadDoesNotExistController: CLDUploaderWidgetDelegate {\n    func uploadWidget(_ widget: CLDUploaderWidget, willCall uploadRequests: [CLDUploadRequest]) {\n        DispatchQueue.main.async {\n            self.showUploadingView()\n        }\n      uploadRequests[0].response( { response, error in\n          self.delegate.switchToController(.UploadExist, url: response?.secureUrl)\n          self.hideUploadingView()\n      } )\n    }\n    func widgetDidCancel(_ widget: CLDUploaderWidget) {\n    }\n    func uploadWidgetDidDismiss() {\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Upload/UploadChoiceController.swift",
    "content": "//\n//  UploadChoiceController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 30/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nprotocol UploadChoiceControllerDelegate: AnyObject {\n    func switchToController(_ uploadState: UploadChoiceState, url: String?)\n    func dismissController()\n}\n\nclass UploadChoiceController: UIViewController {\n\n    @IBOutlet weak var vwContainer: UIView!\n\n    var currentController: UIViewController!\n\n    var type: UploadViewType = .Upload\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        if CloudinaryHelper.shared.getUploadCloud() == nil {\n            setContainerView(.NoCloudName)\n        } else {\n            if CoreDataHelper.shared.fetchData()?.count ?? 0 <= 0 {\n                setContainerView(.NoUpload)\n            } else {\n                setContainerView(.UploadExist)\n            }\n        }\n    }\n\n    private func setContainerView(_ uploadState: UploadChoiceState, url: String? = nil) {\n        removeCurrentController()\n        switch uploadState {\n        case .NoCloudName:\n            currentController = UIStoryboard(name: \"UploadNoCloud\", bundle: nil).instantiateViewController(identifier: \"UploadNoCloudController\")\n            (currentController as! UploadNoCloudController).delegate = self\n//            currentController.modalPresentationStyle = .fullScreen\n            self.present(currentController, animated: true)\n            break\n        case .NoUpload:\n            currentController = UIStoryboard(name: \"UploadDoesNotExist\", bundle: nil).instantiateViewController(identifier: \"UploadDoesNotExistController\")\n            currentController.view.frame = vwContainer.bounds\n            (currentController as! UploadDoesNotExistController).type = type\n            (currentController as! UploadDoesNotExistController).delegate = self\n            addChild(currentController)\n            vwContainer.addSubview(currentController.view)\n            currentController.didMove(toParent: self)\n        case .UploadExist:\n            currentController = UIStoryboard(name: \"SingleUpload\", bundle: nil).instantiateViewController(identifier: \"SingleUploadViewController\")\n            currentController.view.frame = vwContainer.bounds\n            (currentController as! SingleUploadViewController).type = type\n            (currentController as! SingleUploadViewController).delegate = self\n            (currentController as! SingleUploadViewController).url = url\n            addChild(currentController)\n            vwContainer.addSubview(currentController.view)\n            currentController.didMove(toParent: self)\n        }\n    }\n\n    private func removeCurrentController() {\n        currentController?.willMove(toParent: nil)\n        currentController?.view.removeFromSuperview()\n        currentController?.removeFromParent()\n    }\n}\n\nextension UploadChoiceController: UploadChoiceControllerDelegate {\n    func switchToController(_ uploadState: UploadChoiceState, url: String?) {\n        setContainerView(uploadState, url: url)\n    }\n\n    func dismissController() {\n        self.dismiss(animated: true)\n    }\n}\n\nenum UploadChoiceState {\n    case NoCloudName\n    case NoUpload\n    case UploadExist\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Upload/UploadNoCloudController.swift",
    "content": "//\n//  UploadNoCloudController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 04/02/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass UploadNoCloudController: UIViewController {\n\n    @IBOutlet weak var tfCloudName: UITextField!\n    @IBOutlet weak var vwGetStarted: UIView!\n    @IBOutlet weak var vwCantFindCloud: UIView!\n    @IBOutlet weak var vwClose: UIView!\n\n    weak var delegate: UploadChoiceControllerDelegate!\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        setTextField()\n        setGetStratedView()\n        setCantFindCloudView()\n        setCloseView()\n    }\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        EventsHandler.shared.logEvent(event: EventObject(name: \"Upload No Cloud\"))\n    }\n\n    private func setTextField() {\n        tfCloudName.delegate = self\n    }\n\n    private func setGetStratedView() {\n        let gesture = UITapGestureRecognizer(target: self, action: #selector(getStratedTap))\n\n        vwGetStarted.addGestureRecognizer(gesture)\n    }\n\n    private func setCloseView() {\n        vwClose.isUserInteractionEnabled = true\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(closeView))\n        vwClose.addGestureRecognizer(tapGesture)\n    }\n\n    private func setCantFindCloudView() {\n        let gesture = UITapGestureRecognizer(target: self, action: #selector(cantFindCloudClicked))\n\n        vwCantFindCloud.addGestureRecognizer(gesture)\n    }\n\n    @objc private func cantFindCloudClicked() {\n        if let url = URL(string: \"https://cloudinary.com/documentation/how_to_integrate_cloudinary#create_and_explore_your_account\") {\n            UIApplication.shared.open(url, options: [:], completionHandler: nil)\n        }\n    }\n\n    @objc private func getStratedTap() {\n        CloudinaryHelper.shared.setUploadCloud(tfCloudName.text)\n        delegate.switchToController(.NoUpload, url: nil)\n        self.dismiss(animated: true)\n    }\n\n    @objc private func closeView() {\n          self.dismiss(animated: true) {\n              self.delegate.dismissController()\n          }\n      }\n}\n\nextension UploadNoCloudController: UITextFieldDelegate {\n    func textFieldShouldReturn(_ textField: UITextField) -> Bool {\n        getStratedTap()\n        tfCloudName.resignFirstResponder()\n        return false\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Upload/UploadViewController.swift",
    "content": "//\n//  UploadViewController.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 18/09/2023.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\n\nclass UploadViewController: UIViewController {\n\n    @IBOutlet weak var lbTitle: UILabel!\n    @IBOutlet weak var vwUpload: InnerUploadFrame!\n    @IBOutlet weak var vwUploadLarge: InnerUploadFrame!\n    @IBOutlet weak var vwFetchUpload: InnerUploadFrame!\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n    }\n    \n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setViews()\n        EventsHandler.shared.logEvent(event: EventObject(name: \"Upload\"))\n    }\n\n    private func setViews() {\n        setUploadView()\n        setUploadLargeView()\n        setFetchUploadView()\n    }\n\n    private func setUploadView() {\n        vwUpload.setTitle(title: \"Upload\")\n        vwUpload.setSubtitle(subtitle: \"Everything starts when you uploads a file\")\n\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(uploadClicked))\n        vwUpload.addGestureRecognizer(tapGesture)\n    }\n\n    private func setUploadLargeView() {\n        vwUploadLarge.setTitle(title: \"Upload large file\")\n        vwUploadLarge.setSubtitle(subtitle: \"Share your big files up to 100GB\")\n\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(uploadLargeClicked))\n        vwUploadLarge.addGestureRecognizer(tapGesture)\n    }\n\n    private func setFetchUploadView() {\n        vwFetchUpload.setTitle(title: \"Fetch Upload\")\n        vwFetchUpload.setSubtitle(subtitle: \"Upload image from any URL to your cloud\")\n\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(fetchUploadClicked))\n        vwFetchUpload.addGestureRecognizer(tapGesture)\n    }\n\n    @objc private func uploadClicked() {\n        if let controller = UIStoryboard(name: \"Base\", bundle: nil).instantiateViewController(identifier: \"BaseViewController\") as? BaseViewController {\n            controller.type = .Upload\n            controller.modalPresentationStyle = .fullScreen\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n\n    @objc private func uploadLargeClicked() {\n        if let controller = UIStoryboard(name: \"Base\", bundle: nil).instantiateViewController(identifier: \"BaseViewController\") as? BaseViewController {\n            controller.type = .UploadLarge\n            controller.modalPresentationStyle = .fullScreen\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n\n    @objc private func fetchUploadClicked() {\n        if let controller = UIStoryboard(name: \"Base\", bundle: nil).instantiateViewController(identifier: \"BaseViewController\") as? BaseViewController {\n            controller.type = .FetchUpload\n            controller.modalPresentationStyle = .fullScreen\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n}\n\n\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Video/Video Feed/VideoFeedCell.swift",
    "content": "//\n//  VideoFeedCell.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 31/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass VideoFeedCell: UICollectionViewCell {\n\n    @IBOutlet weak var vwGradientView: GradientView!\n    @IBOutlet weak var ivMain: UIImageView!\n\n    func setImage(_ index: Int) {\n        self.layer.cornerRadius = 4\n        self.layer.masksToBounds = false\n        vwGradientView.layer.cornerRadius = 4\n        vwGradientView.layer.masksToBounds = false\n        switch index {\n        case 0:\n            ivMain.image = UIImage(named: \"tiktok\")\n        case 1:\n            ivMain.image = UIImage(named: \"instagram\")\n        case 2:\n            ivMain.image = UIImage(named: \"youtube\")\n        default:\n            break\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Inner Views/Video/VideoFeedCollectionController.swift",
    "content": "//\n//  VideoFeedCollectionController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 31/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nprotocol VideoFeedCollectionDelegate {\n    func cellClicked(_ index: Int)\n}\n\nclass VideoFeedCollectionController: NSObject, UICollectionViewDelegate, UICollectionViewDataSource {\n\n    var delegate: VideoFeedCollectionDelegate\n\n    init(_ delegate: VideoFeedCollectionDelegate) {\n        self.delegate = delegate\n    }\n\n    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {\n        return 3\n    }\n    \n    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {\n        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: \"videoFeedCell\", for: indexPath) as! VideoFeedCell\n        cell.setImage(indexPath.row)\n        cell.layer.cornerRadius = 4\n        cell.layer.masksToBounds = false\n        cell.contentView.layer.cornerRadius = 4\n        cell.contentView.layer.masksToBounds = false\n        return cell\n    }\n\n    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {\n        delegate.cellClicked(indexPath.row)\n    }\n\n\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/MainViewController.swift",
    "content": "//\n//  ViewController.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 11/09/2023.\n//\n\nimport UIKit\n\nclass MainViewController: UIViewController {\n    @IBOutlet weak var vwToolbar: UIView!\n    @IBOutlet weak var vwContainer: UIView!\n\n    var selectedOption: ToolbarOptions = .Delivery\n\n    var currentViewController: UIViewController!\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        setToolbar()\n        setContainerView(option: .Delivery)\n    }\n\n    private func setToolbar() {\n        let bottomToolbar = Toolbar(frame: vwToolbar.bounds, delegate: self)\n        vwToolbar.addSubview(bottomToolbar)\n    }\n\n    private func setContainerView(option: ToolbarOptions) {\n        var controller: UIViewController?\n        switch option {\n        case .Delivery:\n            controller = UIStoryboard(name: \"Delivery\", bundle: nil).instantiateViewController(identifier: \"DeliveryViewController\")\n            break\n        case .Upload:\n            controller = UIStoryboard(name: \"Upload\", bundle: nil).instantiateViewController(identifier: \"UploadViewController\")\n            break\n        case .Widgets:\n            controller = UIStoryboard(name: \"Widgets\", bundle: nil).instantiateViewController(identifier: \"WidgetsViewController\")\n            break\n        case .Video:\n            controller = UIStoryboard(name: \"Video\", bundle: nil).instantiateViewController(identifier: \"VideoViewController\")\n            break\n        }\n        guard let newController = controller else {\n            return\n        }\n        addChild(newController)\n        AnimationHelper.animateTabController(vwContainer, newController, currentViewController: currentViewController, completion: {\n            self.currentViewController?.removeFromParent()\n\n            self.currentViewController = newController\n            newController.didMove(toParent: self)\n        })\n    }\n}\n\n    extension MainViewController: ToolbarDelegate {\n        func deliverySelected() {\n            if(selectedOption != .Delivery) {\n                selectedOption = .Delivery\n                setContainerView(option: .Delivery)\n            }\n        }\n\n        func uploadSelected() {\n            if(selectedOption != .Upload) {\n                selectedOption = .Upload\n                setContainerView(option: .Upload)\n            }\n        }\n\n        func widgetsSelected() {\n            if(selectedOption != .Widgets) {\n                selectedOption = .Widgets\n                setContainerView(option: .Widgets)\n            }\n        }\n\n        func videoSelected() {\n            if(selectedOption != .Video) {\n                selectedOption = .Video\n                setContainerView(option: .Video)\n            }\n        }\n    }\n\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/SplashViewController.swift",
    "content": "//\n//  SplashController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 27/12/2023.\n//\n\nimport Foundation\nimport UIKit\nclass SplashViewController: UIViewController {\n    override func viewDidAppear(_ animated: Bool) {\n        super.viewDidAppear(animated)\n        let delayInSeconds: TimeInterval = 2\n        DispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds) {\n            self.transitionToMainController()\n        }\n        EventsHandler.shared.logEvent(event: EventObject(name: \"Splash\"))\n    }\n\n    func transitionToMainController() {\n        // Instantiate your main view controller\n        let storyboard = UIStoryboard(name: \"Main\", bundle: nil) // Replace \"Main\" with your actual storyboard name\n        let mainViewController = storyboard.instantiateViewController(withIdentifier: \"MainViewController\") // Replace \"MainViewController\" with your actual view controller identifier\n\n        // Transition to the main view controller\n        if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,\n           let delegate = windowScene.delegate as? SceneDelegate {\n            delegate.window?.rootViewController = mainViewController\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Video Feed/Controllers/MainPageController.swift",
    "content": "//\n//  MainPageController.swift\n//  ios-video-testing\n//\n//  Created by Adi Mizrahi on 16/11/2023.\n//\n\nimport Foundation\nimport UIKit\n\nclass MainPageController: UIPageViewController {\n\n    var videoControllersList = [UIViewController]()\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        let videoLinksData = VideoHelper.parsePlist() ?? [String]()\n\n        for link in videoLinksData {\n            if let controller = UIStoryboard(name: \"VideoFeed\", bundle: nil).instantiateViewController(identifier: \"VideoFeedContainerController\") as? VideoFeedContainerController {\n                _ = controller.view\n                controller.videoURL = link\n                controller.setupPlayer()\n                controller.modalPresentationStyle = .fullScreen\n                videoControllersList.append(controller)\n            }\n        }\n        self.dataSource = self\n        (videoControllersList[0] as! VideoFeedContainerController).playVideo()\n        setViewControllers([videoControllersList[0]], direction: .forward, animated: true, completion: nil)\n    }\n}\n\nextension MainPageController: UIPageViewControllerDataSource {\n  func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {\n    let indexOfCurrentPageViewController = videoControllersList.index(of: viewController)!\n    if indexOfCurrentPageViewController == 0 {\n     return nil // To show there is no previous page\n    } else {\n      // Previous UIViewController instance\n        guard let controller = videoControllersList[indexOfCurrentPageViewController - 1] as? VideoFeedContainerController else {\n            return videoControllersList[indexOfCurrentPageViewController - 1]\n        }\n        controller.playVideo()\n      return videoControllersList[indexOfCurrentPageViewController - 1]\n    }\n  }\n\n  func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {\n    let indexOfCurrentPageViewController = videoControllersList.index(of: viewController)!\n    if indexOfCurrentPageViewController == videoControllersList.count - 1 {\n      return nil // To show there is no next page\n    } else {\n      // Next UIViewController instance\n        guard let controller = videoControllersList[indexOfCurrentPageViewController + 1] as? VideoFeedContainerController else {\n            return videoControllersList[indexOfCurrentPageViewController + 1]\n        }\n        controller.playVideo()\n        return videoControllersList[indexOfCurrentPageViewController + 1]\n    }\n  }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Video Feed/Controllers/VideoFeedContainerController.swift",
    "content": "//\n//  VideoFeedContainerController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 04/02/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass VideoFeedContainerController: UIViewController {\n    @IBOutlet weak var vwFeedContainer: UIView!\n    var videoURL: String!\n    var controller: VideoFeedViewController!\n\n\n    func setupPlayer() {\n        if isViewLoaded == false {\n            _ = view\n        }\n\n        controller = UIStoryboard(name: \"VideoFeed\", bundle: nil).instantiateViewController(identifier: \"VideoFeedViewController\")\n        if let controller = controller {\n            controller.videoURL = videoURL\n            controller.setupPlayer()\n\n            controller.view.frame = vwFeedContainer.bounds\n            vwFeedContainer.addSubview(controller.view)\n            controller.didMove(toParent: self)\n        }\n    }\n\n    func playVideo() {\n        controller.playVideo()\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Video Feed/Controllers/VideoFeedController.swift",
    "content": "//\n//  VideoFeedController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 04/02/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass VideoFeedController: UIViewController {\n    @IBOutlet weak var vwBack: UIView!\n    \n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setBackButton()\n    }\n\n    override func viewDidAppear(_ animated: Bool) {\n        super.viewDidAppear(animated)\n        self.view.bringSubviewToFront(vwBack)\n    }\n\n    private func setBackButton() {\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(backClicked))\n        vwBack.addGestureRecognizer(tapGesture)\n    }\n\n\n    @objc private func backClicked() {\n        self.dismiss(animated: true)\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Video Feed/Controllers/VideoFeedViewController.swift",
    "content": "import Foundation\nimport Cloudinary\nimport UIKit\nimport AVKit\n\nclass VideoFeedViewController: UIViewController {\n    \n    var videoURL: String?\n    @IBOutlet weak var vwVideoView: UIView!\n    @IBOutlet weak var vwVideoOverlay: UIView!\n    \n    private var player: CLDVideoPlayer?\n    \n    static func getInstance(url: String) -> VideoFeedViewController {\n        let storyboard = UIStoryboard(name: \"VideoFeed\", bundle: nil)\n        guard let viewController = storyboard.instantiateViewController(withIdentifier: \"VideoFeedViewController\") as? VideoFeedViewController else {\n            fatalError(\"Unable to instantiate VideoFeedViewController from the storyboard.\")\n        }\n        viewController.videoURL = url\n        return viewController\n    }\n    \n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        EventsHandler.shared.logEvent(event: EventObject(name: \"Video Feed\"))\n    }\n    \n    override func viewDidAppear(_ animated: Bool) {\n        super.viewDidAppear(animated)\n    }\n    \n    private func addVideoOverlay(_ playerController: AVPlayerViewController) {\n        // Load the view controller from the \"VideoSocialOverlay\" storyboard\n        let overlayViewController = UIStoryboard(name: \"VideoSocialOverlays\", bundle: nil).instantiateViewController(withIdentifier: \"VideoSocialOverlaysController\")\n        \n        // Add the overlay view controller as a child of AVPlayerViewController\n        playerController.addChild(overlayViewController)\n        overlayViewController.didMove(toParent: playerController)\n        \n        // Add the overlay view controller's view as a subview to playerController's contentOverlayView\n        playerController.contentOverlayView?.addSubview(overlayViewController.view)\n        overlayViewController.view.frame = playerController.contentOverlayView?.bounds ?? .zero\n        overlayViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]\n    }\n    \n    func setupPlayer() {\n        guard let videoURLString = videoURL else {\n            return\n        }\n        \n        if isViewLoaded == false {\n            _ = view\n        }\n        \n        player = CLDVideoPlayer(url: videoURLString)\n        player?.isMuted = true\n        let playerController = AVPlayerViewController()\n        playerController.player = player\n        addChild(playerController)\n        playerController.videoGravity = .resizeAspectFill\n        playerController.showsPlaybackControls = false\n        vwVideoView.addSubview(playerController.view)\n        playerController.view.frame = vwVideoView.bounds\n        playerController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]\n        playerController.didMove(toParent: self)\n        NotificationCenter.default.addObserver(self,\n                                               selector: #selector(playerItemDidReachEnd),\n                                               name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,\n                                               object: player?.currentItem)\n        \n        addVideoOverlay(playerController)\n    }\n    \n    func playVideo() {\n        player?.play()\n    }\n    \n    @objc func playerItemDidReachEnd() {\n        // Seek to the start of the video to loop it\n        player?.seek(to: CMTime.zero)\n        player?.play()\n    }\n    \n    deinit {\n        NotificationCenter.default.removeObserver(self)\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Video Feed/Controllers/VideoSocialOverlaysController.swift",
    "content": "//\n//  VideoSocialOverlaysController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 04/02/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass VideoSocialOverlaysController: UIViewController {\n    \n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Video Feed/Controllers/VideoViewController.swift",
    "content": "//\n//  VideoViewController.swift\n//  ios-video-testing\n//\n//  Created by Adi Mizrahi on 16/11/2023.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\nimport AVKit\n\nclass VideoViewController: UIViewController {\n\n    @IBOutlet weak var vwVideoView: UIView!\n\n    @IBOutlet weak var cvVideoFeed: UICollectionView!\n\n    var collectionController: VideoFeedCollectionController!\n\n    var playerController: AVPlayerViewController!\n    var player: CLDVideoPlayer!\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n    }\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setVideoView()\n        setVideoFeedCollectionView()\n        EventsHandler.shared.logEvent(event: EventObject(name: \"Video\"))\n    }\n\n    private func setVideoView() {\n        player = CLDVideoPlayer(url: \"https://res.cloudinary.com/mobiledemoapp/video/upload/v1706627936/Demo%20app%20content/sport-1_tjwumh.mp4\")\n        playerController = AVPlayerViewController()\n        playerController.player = player\n        addChild(playerController)\n        playerController.videoGravity = .resizeAspectFill\n        vwVideoView.addSubview(playerController.view)\n        playerController.view.frame = vwVideoView.bounds\n        playerController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]\n        playerController.didMove(toParent: self)\n    }\n\n    private func setVideoFeedCollectionView() {\n        collectionController = VideoFeedCollectionController(self)\n        cvVideoFeed.delegate = collectionController\n        cvVideoFeed.dataSource = collectionController\n    }\n\n    @objc func playerDidFinishPlaying(note: NSNotification) {\n        player.seek(to: .zero) // Seek to the beginning of the video\n        player.play()\n    }\n}\n\nextension VideoViewController: VideoFeedCollectionDelegate {\n    func cellClicked(_ index: Int) {\n        if let controller = UIStoryboard(name: \"VideoFeed\", bundle: nil).instantiateViewController(identifier: \"VideoFeedController\") as? VideoFeedController {\n            controller.modalPresentationStyle = .fullScreen\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Video Feed/Helpers/VideoHelper.swift",
    "content": "//\n//  VideoHelper.swift\n//  ios-video-testing\n//\n//  Created by Adi Mizrahi on 16/11/2023.\n//\n\nimport Foundation\nclass VideoHelper {\n    static func parsePlist() -> [String]? {\n        if let path = Bundle.main.path(forResource: \"video_links\", ofType: \"plist\") {\n            let videoDictonary = NSDictionary(contentsOfFile: path)\n            if let videoLinks = videoDictonary?.allValues as? [String] {\n                return videoLinks\n            }\n\n        }\n        return nil\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Video Feed/Resources/video_links.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>video1</key>\n\t<string>https://res.cloudinary.com/mobiledemoapp/video/upload/ar_9:16,c_fill,g_auto,w_600/f_auto:video,q_auto:eco/sprort-2_zgsr5k.mp4</string>\n\t<key>video2</key>\n\t<string>https://res.cloudinary.com/mobiledemoapp/video/upload/ar_9:16,c_fill,g_auto,w_600/f_auto:video,q_auto:eco/fashion-2_ewukga.mp4</string>\n\t<key>video3</key>\n\t<string>https://res.cloudinary.com/demo/video/upload/ar_9:16,c_fill,g_auto,w_600/f_auto:video,q_auto:eco/v1/docs/surfers</string>\n\t<key>video4</key>\n\t<string>https://res.cloudinary.com/mobiledemoapp/video/upload/ar_9:16,c_fill,g_auto,w_600/f_auto:video,q_auto:eco/fashion-1_1_kuwihy.mp4</string>\n\t<key>video5</key>\n\t<string>https://res.cloudinary.com/demo/video/upload/ar_9:16,c_fill,g_auto,w_600/f_auto:video,q_auto:eco/v1/docs/car-film</string>\n\t<key>video6</key>\n\t<string>https://res.cloudinary.com/demo/video/upload/ar_9:16,c_fill,g_auto,w_600/f_auto:video,q_auto:eco/v1/docs/rocky-mountains</string>\n\t<key>video7</key>\n\t<string>https://res.cloudinary.com/demo/video/upload/ar_9:16,c_fill,g_auto,w_600/f_auto:video,q_auto:eco/v1/docs/sailing_boat</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Widgets/ImageWidgetViewController.swift",
    "content": "//\n//  ImageWidgetViewController.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 19/09/2023.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\n\nclass ImageWidgetViewController: UIViewController {\n    @IBOutlet weak var ivLocal: CLDUIImageView!\n    @IBOutlet weak var ivRemote: CLDUIImageView!\n    @IBOutlet weak var ivCloudinary: CLDUIImageView!\n\n    let cloudinary = CloudinaryHelper.shared.cloudinary\n\n    \n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setLocalImage()\n        setRemoteImage()\n        setCloudinaryImage()\n        EventsHandler.shared.logEvent(event: EventObject(name: \"Image Widget\"))\n    }\n\n    private func setLocalImage() {\n        ivLocal.image = UIImage(named: \"house\")\n    }\n\n    private func setRemoteImage() {\n        ivRemote.cldSetImage(\"https://res.cloudinary.com/mobiledemoapp/image/upload/v1706628181/Demo%20app%20content/Frame_871_ao5o4r.jpg\", cloudinary: cloudinary)\n    }\n\n    private func setCloudinaryImage() {\n        ivCloudinary.cldSetImage(publicId: \"Demo%20app%20content/Frame_871_ao5o4r\", cloudinary: cloudinary)\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Widgets/UploadWidgetViewController.swift",
    "content": "//\n//  UploadWidgetViewController.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 19/09/2023.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\n\nclass UploadWidgetViewController: UIViewController {\n\n    @IBOutlet weak var vwUploadContainer: UIView!\n    @IBOutlet weak var aiLoading: UIActivityIndicatorView!\n    @IBOutlet weak var ivMain: CLDUIImageView!\n    @IBOutlet weak var vwOpenGallery: UIView!\n\n    var cloudinary: CLDCloudinary!\n    var uploadWidget: CLDUploaderWidget!\n\n    var noCloudController: UIViewController!\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        setUploadButton()\n    }\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        if CloudinaryHelper.shared.getUploadCloud() == nil {\n            openNoCloudController()\n        } else {\n            cloudinary = CLDCloudinary(configuration: CLDConfiguration(cloudName: CloudinaryHelper.shared.getUploadCloud()!))\n        }\n        EventsHandler.shared.logEvent(event: EventObject(name: \"Upload Widget\"))\n    }\n\n    func setUploadButton() {\n        vwOpenGallery.layer.cornerRadius = vwOpenGallery.frame.height / 2\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(openUploadWidget))\n        vwOpenGallery.addGestureRecognizer(tapGesture)\n    }\n\n    @objc func openUploadWidget() {\n        let configuration = CLDWidgetConfiguration(\n          uploadType: CLDUploadType(signed: false, preset: \"ios_sample\"))\n\n        uploadWidget = CLDUploaderWidget(\n          cloudinary: cloudinary,\n          configuration: configuration,\n          images: nil,\n          delegate: self)\n\n        uploadWidget.presentWidget(from: self)\n    }\n\n    @objc func stepBack() {\n        self.dismiss(animated: true)\n    }\n\n    private func showUploadingView() {\n        vwUploadContainer.isHidden = true\n        aiLoading.isHidden = false\n\n    }\n\n    private func hideUploadingView() {\n        self.aiLoading.isHidden = true\n    }\n\n    private func openNoCloudController() {\n        noCloudController = UIStoryboard(name: \"UploadNoCloud\", bundle: nil).instantiateViewController(identifier: \"UploadNoCloudController\")\n        (noCloudController as! UploadNoCloudController).delegate = self\n//            currentController.modalPresentationStyle = .fullScreen\n        self.present(noCloudController, animated: true)\n    }\n}\n\nextension UploadWidgetViewController: CLDUploaderWidgetDelegate {\n    func uploadWidget(_ widget: CLDUploaderWidget, willCall uploadRequests: [CLDUploadRequest]) {\n      uploadRequests[0].response( { response, error in\n          self.hideUploadingView()\n          self.ivMain.cldSetImage(response!.secureUrl!, cloudinary: self.cloudinary)\n      } )\n    }\n    func widgetDidCancel(_ widget: CLDUploaderWidget) {\n    }\n    func uploadWidgetDidDismiss() {\n        showUploadingView()\n    }\n}\n\nextension UploadWidgetViewController: UploadChoiceControllerDelegate {\n    func switchToController(_ uploadState: UploadChoiceState, url: String?) {\n        showUploadingView()\n        cloudinary = CLDCloudinary(configuration: CLDConfiguration(cloudName: CloudinaryHelper.shared.getUploadCloud()!))\n        if noCloudController != nil {\n            noCloudController.dismiss(animated: true)\n        }\n    }\n\n    func dismissController() {\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Controllers/Widgets/WidgetsViewController.swift",
    "content": "//\n//  WidgetsViewController.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 25/01/2024.\n//\n\nimport Foundation\nimport UIKit\nimport Cloudinary\nimport AVKit\n\nclass WidgetsViewController: UIViewController {\n\n    @IBOutlet weak var vwImageWidgetVideo: UIView!\n    @IBOutlet weak var vwUploadWidget: UIView!\n    @IBOutlet weak var vwImageWidget: UIView!\n    @IBOutlet weak var vwUploadWidgetVideo: UIView!\n\n    var imageWidgetplayer: CLDVideoPlayer!\n    var uploadWidgetplayer: CLDVideoPlayer!\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        setUploadWidgetView()\n        setImageWidgetView()\n    }\n\n    override func viewWillAppear(_ animated: Bool) {\n        super.viewWillAppear(animated)\n        setUploadWidgetVideo()\n        setImageWidgetVideo()\n        EventsHandler.shared.logEvent(event: EventObject(name: \"Widgets\"))\n    }\n\n    private func setImageWidgetVideo() {\n        imageWidgetplayer = CLDVideoPlayer(publicId: \"DevApp_ImageUpload_02_vpsz7p\", cloudinary: CloudinaryHelper.shared.cloudinary)\n        configurePlayer(imageWidgetplayer, in: vwImageWidgetVideo)\n    }\n\n    private func setUploadWidgetVideo() {\n        uploadWidgetplayer = CLDVideoPlayer(publicId: \"DevApp_UploadWidget_02_r61cfi\", cloudinary: CloudinaryHelper.shared.cloudinary)\n        configurePlayer(uploadWidgetplayer, in: vwUploadWidgetVideo)\n    }\n\n    private func configurePlayer(_ player: CLDVideoPlayer, in view: UIView) {\n        let playerLayer = AVPlayerLayer(player: player)\n        view.backgroundColor = .black\n        playerLayer.frame = view.bounds\n        playerLayer.videoGravity = .resizeAspectFill\n        view.layer.addSublayer(playerLayer)\n\n        // Add observer for AVPlayerItemDidPlayToEndTime\n        NotificationCenter.default.addObserver(self,\n                                               selector: #selector(playerItemDidReachEnd),\n                                               name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,\n                                               object: player.currentItem)\n\n        player.play()\n    }\n\n    @objc private func playerItemDidReachEnd(notification: Notification) {\n        if let playerItem = notification.object as? AVPlayerItem {\n            // Seek to the start of the video to loop it\n            playerItem.seek(to: .zero)\n            uploadWidgetplayer.play()\n            imageWidgetplayer.play()\n\n        }\n    }\n\n    deinit {\n        NotificationCenter.default.removeObserver(self)\n    }\n\n    private func setUploadWidgetView() {\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(uploadWidgetClicked))\n        vwUploadWidget.addGestureRecognizer(tapGesture)\n    }\n\n    private func setImageWidgetView() {\n        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(imageWidgetClicked))\n        vwImageWidget.addGestureRecognizer(tapGesture)\n    }\n\n    @objc private func uploadWidgetClicked() {\n        if let controller = UIStoryboard(name: \"Base\", bundle: nil).instantiateViewController(identifier: \"BaseViewController\") as? BaseViewController {\n            controller.type = .UploadWidget\n            controller.modalPresentationStyle = .fullScreen\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n\n    @objc private func imageWidgetClicked() {\n        if let controller = UIStoryboard(name: \"Base\", bundle: nil).instantiateViewController(identifier: \"BaseViewController\") as? BaseViewController {\n            controller.type = .ImageWidget\n            controller.modalPresentationStyle = .fullScreen\n            self.present(controller, animated: true, completion: nil)\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Core Data/AssetItems+CoreDataClass.swift",
    "content": "//\n//  AssetItems_CoreDataClass.swift\n//  Cloudinary_Example\n//\n//  Created by Adi Mizrahi on 18/07/2024.\n//  Copyright © 2024 CocoaPods. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\npublic class AssetItems: NSManagedObject {\n\n}\n"
  },
  {
    "path": "Example/Cloudinary/Core Data/AssetItems+CoreDataProperties.swift",
    "content": "//\n//  AssetItems+CoreDataProperties.swift\n//  Cloudinary_Example\n//\n//  Created by Adi Mizrahi on 18/07/2024.\n//  Copyright © 2024 CocoaPods. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\n\n\nextension AssetItems {\n\n    @nonobjc public class func fetchRequest() -> NSFetchRequest<AssetItems> {\n        return NSFetchRequest<AssetItems>(entityName: \"AssetItems\")\n    }\n\n    @NSManaged public var deliveryType: String\n    @NSManaged public var assetType: String\n    @NSManaged public var transformation: String?\n    @NSManaged public var publicId: String\n    @NSManaged public var url: String\n\n}\n\nextension AssetItems : Identifiable {\n\n}\n"
  },
  {
    "path": "Example/Cloudinary/Core Data/AssetModel.swift",
    "content": "//\n//  AssetModel.swift\n//  Cloudinary_Example\n//\n//  Created by Adi Mizrahi on 18/07/2024.\n//  Copyright © 2024 CocoaPods. All rights reserved.\n//\n\nimport Foundation\nclass AssetModel {\n     private var deliveryType: String\n     private var assetType: String\n     private var transformation: String?\n     private var publicId: String\n    private var url: String\n\n    init(deliveryType: String, assetType: String, transformation: String? = nil, publicId: String, url: String) {\n        self.deliveryType = deliveryType\n        self.assetType = assetType\n        self.transformation = transformation\n        self.publicId = publicId\n        self.url = url\n    }\n\n    func setDeliveryType(_ type: String) {\n        deliveryType = type\n    }\n\n    func setAssetType(_ type: String) {\n        assetType = type\n    }\n\n    func setTransformation(_ trans: String) {\n        transformation = trans\n    }\n\n    func setPublicId(_ id: String) {\n        publicId = id\n    }\n\n    func setUrl(_ url: String) {\n        self.url = url\n    }\n\n    func getDeliveryType() -> String {\n        return deliveryType\n    }\n\n    func getAssetType() -> String {\n        return assetType\n    }\n\n    func getTransformation() -> String? {\n        return transformation\n    }\n\n    func getPublicId() -> String {\n        return publicId\n    }\n\n    func getUrl() -> String {\n        return url\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Core Data/AssetModel.xcdatamodeld/Model.xcdatamodel/contents",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<model type=\"com.apple.IDECoreDataModeler.DataModel\" documentVersion=\"1.0\" lastSavedToolsVersion=\"22522\" systemVersion=\"22G120\" minimumToolsVersion=\"Automatic\" sourceLanguage=\"Swift\" usedWithSwiftData=\"YES\" userDefinedModelVersionIdentifier=\"\">\n    <entity name=\"AssetItems\" representedClassName=\".AssetItems\" syncable=\"YES\">\n        <attribute name=\"assetType\" optional=\"YES\" attributeType=\"String\"/>\n        <attribute name=\"deliveryType\" optional=\"YES\" attributeType=\"String\"/>\n        <attribute name=\"publicId\" optional=\"YES\" attributeType=\"String\"/>\n        <attribute name=\"transformation\" optional=\"YES\" attributeType=\"String\"/>\n        <attribute name=\"url\" optional=\"YES\" attributeType=\"String\"/>\n    </entity>\n</model>"
  },
  {
    "path": "Example/Cloudinary/Core Data/CoreDataHelper.swift",
    "content": "//\n//  CoreDataHelper.swift\n//  Cloudinary_Example\n//\n//  Created by Adi Mizrahi on 18/07/2024.\n//  Copyright © 2024 CocoaPods. All rights reserved.\n//\n\nimport Foundation\nimport CoreData\nclass CoreDataHelper {\n\n    static let shared = CoreDataHelper()\n\n    lazy var persistentContainer: NSPersistentContainer = {\n        let container = NSPersistentContainer(name: \"AssetModel\")\n        container.loadPersistentStores(completionHandler: { (storeDescription, error) in\n            if let error = error as NSError? {\n                fatalError(\"Unresolved error \\(error), \\(error.userInfo)\")\n            }\n        })\n        return container\n    }()\n\n    func saveContext() {\n        let context = persistentContainer.viewContext\n        if context.hasChanges {\n            do {\n                try context.save()\n            } catch {\n                let nserror = error as NSError\n                fatalError(\"Unresolved error \\(nserror), \\(nserror.userInfo)\")\n            }\n        }\n    }\n\n    func insertData(_ item: AssetModel) {\n        let context = CoreDataHelper.shared.persistentContainer.viewContext\n        let newDelivery = AssetItems(context: context)\n        newDelivery.deliveryType = item.getDeliveryType()\n        newDelivery.assetType = item.getAssetType()\n        newDelivery.transformation = item.getTransformation() ?? \"\"\n        newDelivery.publicId = item.getPublicId()\n        newDelivery.url = item.getUrl()\n\n        do {\n            try context.save()\n        } catch {\n            print(\"Error saving context: \\(error)\")\n        }\n    }\n\n    func fetchSingleData(publicId: String) -> AssetModel? {\n        let context = CoreDataHelper.shared.persistentContainer.viewContext\n        let fetchRequest: NSFetchRequest<AssetItems> = AssetItems.fetchRequest()\n\n        do {\n            let items = try context.fetch(fetchRequest)\n            for item in items {\n                if item.publicId == publicId {\n                    return AssetModel(deliveryType: item.deliveryType, assetType: item.assetType, transformation: item.transformation, publicId: item.publicId, url: item.url)\n                }\n            }\n        } catch {\n            print(\"Error fetching data: \\(error)\")\n        }\n        return nil\n    }\n\n    func fetchData() -> [AssetItems]? {\n        let context = CoreDataHelper.shared.persistentContainer.viewContext\n        let fetchRequest: NSFetchRequest<AssetItems> = AssetItems.fetchRequest()\n\n        do {\n            let items = try context.fetch(fetchRequest)\n            return items\n        } catch {\n            print(\"Error fetching data: \\(error)\")\n        }\n        return nil\n    }\n\n}\n"
  },
  {
    "path": "Example/Cloudinary/Custom Views/GradientView.swift",
    "content": "//\n//  GradientView.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 27/12/2023.\n//\n\nimport Foundation\nimport UIKit\n@IBDesignable\nclass GradientView: UIView {\n    @IBInspectable var firstColor: UIColor = UIColor.clear {\n        didSet {\n            updateView()\n        }\n    }\n    @IBInspectable var secondColor: UIColor = UIColor.clear {\n        didSet {\n            updateView()\n        }\n    }\n\n    override class var layerClass: AnyClass {\n        get {\n            return CAGradientLayer.self\n        }\n    }\n\n    override func layoutSubviews() {\n        super.layoutSubviews()\n        updateView()\n    }\n\n    func updateView() {\n        guard let gradientLayer = layer as? CAGradientLayer else { return }\n\n        gradientLayer.colors = [UIColor(red: 0.204, green: 0.282, blue: 0.773, alpha: 1).cgColor,\n                                UIColor(red: 0.157, green: 0.733, blue: 0.98, alpha: 1).cgColor\n                                ]\n        gradientLayer.locations = [0, 1]\n        gradientLayer.startPoint = CGPoint(x: 0, y: 0) // Top-left\n               gradientLayer.endPoint = CGPoint(x: 1, y: 1)   // Bottom-right\n//        gradientLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransform(a: 0.98, b: 0.98, c: -0.98, d: 0.45, tx: 0.5, ty: -0.21))\n        gradientLayer.position = self.center\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Custom Views/RevealImageView.swift",
    "content": "//\n//  RevealImageView.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 08/01/2024.\n//\n\nimport Foundation\nimport UIKit\nclass RevealImageView: UIImageView {\n\n    public var leftImage: UIImage? {\n        didSet {\n            if let img = leftImage {\n                leftImageLayer.contents = img.cgImage\n            }\n        }\n    }\n    public var rightImage: UIImage? {\n        didSet {\n            if let img = rightImage {\n                self.image = img\n            }\n        }\n    }\n\n    // private properties\n    private let leftImageLayer = CALayer()\n    private let maskLayer = CALayer()\n    private let lineView = UIView()\n    private var pct: CGFloat = 0.5 {\n        didSet {\n            updateView()\n        }\n    }\n\n    convenience init() {\n        self.init(frame: .zero)\n    }\n    override init(frame: CGRect) {\n        super.init(frame: frame)\n        commonInit()\n    }\n    required init?(coder: NSCoder) {\n        super.init(coder: coder)\n        commonInit()\n    }\n    private func commonInit() {\n        // any opaque color\n        maskLayer.backgroundColor = UIColor.black.cgColor\n        leftImageLayer.mask = maskLayer\n        // the \"reveal\" image layer\n        layer.addSublayer(leftImageLayer)\n\n        // the vertical line\n        lineView.backgroundColor = .white\n        addSubview(lineView)\n\n        isUserInteractionEnabled = true\n    }\n\n    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {\n        guard let t = touches.first\n        else { return }\n        let loc = t.location(in: self)\n        pct = loc.x / bounds.width\n    }\n    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {\n        guard let t = touches.first\n        else { return }\n        let loc = t.location(in: self)\n        pct = loc.x / bounds.width\n    }\n\n    private func updateView() {\n        // move the vertical line to the touch point\n        lineView.frame = CGRect(x: bounds.width * pct, y: bounds.minY, width: 4, height: bounds.height)\n\n        // update the \"left image\" mask to the touch point\n        var r = bounds\n        r.size.width = bounds.width * pct\n\n        // disable layer animation\n        CATransaction.begin()\n        CATransaction.setDisableActions(true)\n        maskLayer.frame = r\n        CATransaction.commit()\n    }\n\n    override func layoutSubviews() {\n        super.layoutSubviews()\n        leftImageLayer.frame = bounds\n        updateView()\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Custom Views/ToolBar/Item/ToolbarItem.swift",
    "content": "//\n//  ToolbarItem.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 27/12/2023.\n//\n\nimport Foundation\nimport UIKit\nclass ToolbarItem: UIView {\n\n    @IBOutlet weak var ivMain: UIImageView!\n    @IBOutlet weak var lbMain: UILabel!\n\n    override init(frame: CGRect) {\n        super.init(frame: frame)\n        commonInit()\n    }\n\n    required init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n        commonInit()\n    }\n\n    private func commonInit() {\n        guard let view = loadViewFromNib() else { return }\n        view.frame = bounds\n        view.autoresizingMask = [.flexibleWidth, .flexibleHeight]\n        addSubview(view)\n    }\n\n    private func loadViewFromNib() -> UIView? {\n        let nib = UINib(nibName: \"ToolbarItem\", bundle: nil)\n        return nib.instantiate(withOwner: self, options: nil).first as? UIView\n    }\n\n    func selectItem() {\n        ivMain.tintColor = UIColor(named: \"primary\")\n        lbMain.textColor = UIColor(named: \"primary\")\n    }\n\n    func unselectItem() {\n        ivMain.tintColor = UIColor(named: \"text_not_selected\")\n        lbMain.textColor = UIColor(named: \"text_not_selected\")\n    }\n}\n\n"
  },
  {
    "path": "Example/Cloudinary/Custom Views/ToolBar/Item/ToolbarItem.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"ToolbarItem\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n            <connections>\n                <outlet property=\"ivMain\" destination=\"tM8-8b-Ier\" id=\"KV2-Nj-Av6\"/>\n                <outlet property=\"lbMain\" destination=\"ZwD-EX-0zt\" id=\"SUo-qJ-804\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"98\" height=\"64\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PGD-yS-8ec\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"98\" height=\"64\"/>\n                    <subviews>\n                        <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QO1-7s-3yO\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"98\" height=\"38.333333333333336\"/>\n                            <subviews>\n                                <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"car-speed-limiter\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tM8-8b-Ier\">\n                                    <rect key=\"frame\" x=\"39\" y=\"13.333333333333336\" width=\"20\" height=\"20\"/>\n                                    <color key=\"tintColor\" name=\"primary\"/>\n                                    <constraints>\n                                        <constraint firstAttribute=\"width\" constant=\"20\" id=\"CNt-Wx-pqi\"/>\n                                        <constraint firstAttribute=\"width\" secondItem=\"tM8-8b-Ier\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"YaK-IZ-r0A\"/>\n                                    </constraints>\n                                </imageView>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                            <constraints>\n                                <constraint firstItem=\"tM8-8b-Ier\" firstAttribute=\"centerX\" secondItem=\"QO1-7s-3yO\" secondAttribute=\"centerX\" id=\"17h-80-lS3\"/>\n                                <constraint firstAttribute=\"bottom\" secondItem=\"tM8-8b-Ier\" secondAttribute=\"bottom\" constant=\"5\" id=\"ste-h7-oUv\"/>\n                            </constraints>\n                        </view>\n                        <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bdG-Hc-yLb\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"38.333333333333336\" width=\"98\" height=\"25.666666666666664\"/>\n                            <subviews>\n                                <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Delivery\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZwD-EX-0zt\">\n                                    <rect key=\"frame\" x=\"26\" y=\"0.0\" width=\"46\" height=\"14.333333333333334\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"12\"/>\n                                    <color key=\"textColor\" name=\"primary\"/>\n                                    <nil key=\"highlightedColor\"/>\n                                </label>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                            <constraints>\n                                <constraint firstItem=\"ZwD-EX-0zt\" firstAttribute=\"top\" secondItem=\"bdG-Hc-yLb\" secondAttribute=\"top\" id=\"3cz-lL-YeS\"/>\n                                <constraint firstItem=\"ZwD-EX-0zt\" firstAttribute=\"centerX\" secondItem=\"bdG-Hc-yLb\" secondAttribute=\"centerX\" id=\"CeF-KY-Tgy\"/>\n                            </constraints>\n                        </view>\n                    </subviews>\n                    <constraints>\n                        <constraint firstItem=\"QO1-7s-3yO\" firstAttribute=\"height\" secondItem=\"PGD-yS-8ec\" secondAttribute=\"height\" multiplier=\"0.6\" id=\"hqR-TX-AyE\"/>\n                    </constraints>\n                </stackView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n            <constraints>\n                <constraint firstItem=\"PGD-yS-8ec\" firstAttribute=\"top\" secondItem=\"iN0-l3-epB\" secondAttribute=\"top\" id=\"HN5-9O-4fw\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"PGD-yS-8ec\" secondAttribute=\"trailing\" id=\"QQz-3V-p67\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"PGD-yS-8ec\" secondAttribute=\"bottom\" id=\"c8F-V7-XF5\"/>\n                <constraint firstItem=\"PGD-yS-8ec\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" id=\"dhr-7v-wWn\"/>\n            </constraints>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"74\" y=\"20\"/>\n        </view>\n    </objects>\n    <resources>\n        <image name=\"car-speed-limiter\" width=\"21\" height=\"20\"/>\n        <namedColor name=\"primary\">\n            <color red=\"0.27450980392156865\" green=\"0.59607843137254901\" blue=\"0.96862745098039216\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Custom Views/ToolBar/Toolbar.swift",
    "content": "//\n//  Toolbar.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 27/12/2023.\n//\n\nimport Foundation\nimport UIKit\n\nprotocol ToolbarDelegate {\n    func deliverySelected()\n    func uploadSelected()\n    func widgetsSelected()\n    func videoSelected()\n}\n\n\nclass Toolbar: UIView {\n    @IBOutlet weak var vwDelivery: ToolbarItem!\n    @IBOutlet weak var vwUpload: ToolbarItem!\n    @IBOutlet weak var vwWidgets: ToolbarItem!\n    @IBOutlet weak var vwVideo: ToolbarItem!\n\n    var delegate: ToolbarDelegate\n\n    init(frame: CGRect, delegate: ToolbarDelegate) {\n        self.delegate = delegate\n        super.init(frame: frame)\n        commonInit()\n    }\n\n    required init?(coder: NSCoder) {\n        fatalError(\"init(coder:) has not been implemented\")\n    }\n\n    private func commonInit() {\n        let nibName = String(describing: type(of: self))\n        if let view = Bundle.main.loadNibNamed(nibName, owner: self, options: nil)?.first as? UIView {\n            view.frame = bounds\n            addSubview(view)\n        }\n        setItems()\n        setupGestures()\n        selectItem(.Delivery)\n    }\n\n    private func setItems() {\n        vwDelivery.ivMain.image = UIImage(named: \"car-speed-limiter\")\n        vwDelivery.lbMain.text = \"Delivery\"\n\n        vwUpload.ivMain.image = UIImage(named: \"upload\")\n        vwUpload.lbMain.text = \"Upload\"\n\n        vwWidgets.ivMain.image = UIImage(named: \"widgets\")\n        vwWidgets.lbMain.text = \"Widgets\"\n\n        vwVideo.ivMain.image = UIImage(named: \"video\")\n        vwVideo.lbMain.text = \"Video\"\n    }\n\n    private func setupGestures() {\n        let deliveryTapGesture = UITapGestureRecognizer(target: self, action: #selector(deliveryViewTapped))\n        vwDelivery.addGestureRecognizer(deliveryTapGesture)\n\n        let uploadTapGesture = UITapGestureRecognizer(target: self, action: #selector(uploadViewTapped))\n        vwUpload.addGestureRecognizer(uploadTapGesture)\n\n        let widgetTapGesture = UITapGestureRecognizer(target: self, action: #selector(widgetsViewTapped))\n        vwWidgets.addGestureRecognizer(widgetTapGesture)\n\n        let videoTapGesture = UITapGestureRecognizer(target: self, action: #selector(videoViewTapped))\n        vwVideo.addGestureRecognizer(videoTapGesture)\n    }\n\n    @objc private func deliveryViewTapped() {\n        selectItem(.Delivery)\n    }\n\n    @objc private func uploadViewTapped() {\n        selectItem(.Upload)\n    }\n\n    @objc private func widgetsViewTapped() {\n        selectItem(.Widgets)\n    }\n\n    @objc private func videoViewTapped() {\n        selectItem(.Video)\n    }\n\n    private func selectItem(_ item: ToolbarOptions) {\n        switch item {\n        case .Delivery:\n            vwDelivery.selectItem()\n            vwUpload.unselectItem()\n            vwWidgets.unselectItem()\n            vwVideo.unselectItem()\n            delegate.deliverySelected()\n            break\n        case .Upload:\n            vwDelivery.unselectItem()\n            vwUpload.selectItem()\n            vwWidgets.unselectItem()\n            vwVideo.unselectItem()\n            delegate.uploadSelected()\n            break\n        case .Widgets:\n            vwDelivery.unselectItem()\n            vwUpload.unselectItem()\n            vwWidgets.selectItem()\n            vwVideo.unselectItem()\n            delegate.widgetsSelected()\n            break\n        case .Video:\n            vwDelivery.unselectItem()\n            vwUpload.unselectItem()\n            vwWidgets.unselectItem()\n            vwVideo.selectItem()\n            delegate.videoSelected()\n            break\n        }\n    }\n\n    private func unselectItem(_ item: ToolbarOptions) {\n        switch item {\n        case .Delivery:\n            break\n        case .Upload:\n            break\n        case .Widgets:\n            break\n        case .Video:\n            break\n        }\n    }\n}\nenum ToolbarOptions {\n    case Delivery\n    case Upload\n    case Widgets\n    case Video\n}\n"
  },
  {
    "path": "Example/Cloudinary/Custom Views/ToolBar/Toolbar.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"Toolbar\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n            <connections>\n                <outlet property=\"vwDelivery\" destination=\"UWR-T8-bP8\" id=\"7sb-Zi-cZG\"/>\n                <outlet property=\"vwUpload\" destination=\"XIC-XR-k7u\" id=\"Gyr-Uw-dQV\"/>\n                <outlet property=\"vwVideo\" destination=\"9ex-DG-EBH\" id=\"KYc-hr-ll8\"/>\n                <outlet property=\"vwWidgets\" destination=\"8ur-CX-ipd\" id=\"qJA-c9-uKp\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"98\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4BX-df-jPb\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"64\"/>\n                    <subviews>\n                        <stackView opaque=\"NO\" contentMode=\"scaleToFill\" distribution=\"fillEqually\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"I7a-Lc-Osd\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"64\"/>\n                            <subviews>\n                                <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UWR-T8-bP8\" customClass=\"ToolbarItem\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"98.333333333333329\" height=\"64\"/>\n                                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                </view>\n                                <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XIC-XR-k7u\" customClass=\"ToolbarItem\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                    <rect key=\"frame\" x=\"98.333333333333343\" y=\"0.0\" width=\"98.333333333333343\" height=\"64\"/>\n                                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                </view>\n                                <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8ur-CX-ipd\" customClass=\"ToolbarItem\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                    <rect key=\"frame\" x=\"196.66666666666666\" y=\"0.0\" width=\"97.999999999999972\" height=\"64\"/>\n                                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                </view>\n                                <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9ex-DG-EBH\" customClass=\"ToolbarItem\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                    <rect key=\"frame\" x=\"294.66666666666669\" y=\"0.0\" width=\"98.333333333333314\" height=\"64\"/>\n                                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                </view>\n                            </subviews>\n                        </stackView>\n                    </subviews>\n                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                    <constraints>\n                        <constraint firstItem=\"I7a-Lc-Osd\" firstAttribute=\"top\" secondItem=\"4BX-df-jPb\" secondAttribute=\"top\" id=\"01F-ox-adY\"/>\n                        <constraint firstAttribute=\"bottom\" secondItem=\"I7a-Lc-Osd\" secondAttribute=\"bottom\" id=\"Pds-5j-VdR\"/>\n                        <constraint firstItem=\"I7a-Lc-Osd\" firstAttribute=\"leading\" secondItem=\"4BX-df-jPb\" secondAttribute=\"leading\" id=\"Tvv-Hu-nlu\"/>\n                        <constraint firstAttribute=\"trailing\" secondItem=\"I7a-Lc-Osd\" secondAttribute=\"trailing\" id=\"VpS-db-ryQ\"/>\n                        <constraint firstAttribute=\"height\" constant=\"64\" id=\"cDZ-Ic-BAp\"/>\n                    </constraints>\n                </view>\n            </subviews>\n            <color key=\"backgroundColor\" name=\"secondary\"/>\n            <constraints>\n                <constraint firstItem=\"4BX-df-jPb\" firstAttribute=\"width\" secondItem=\"iN0-l3-epB\" secondAttribute=\"width\" id=\"9eE-9O-4Ey\"/>\n                <constraint firstItem=\"4BX-df-jPb\" firstAttribute=\"centerX\" secondItem=\"iN0-l3-epB\" secondAttribute=\"centerX\" id=\"fNm-pq-qbN\"/>\n                <constraint firstItem=\"4BX-df-jPb\" firstAttribute=\"top\" secondItem=\"iN0-l3-epB\" secondAttribute=\"top\" id=\"zPn-C2-7LW\"/>\n            </constraints>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"33\" y=\"246\"/>\n        </view>\n    </objects>\n    <resources>\n        <namedColor name=\"secondary\">\n            <color red=\"0.24705882352941178\" green=\"0.27843137254901962\" blue=\"0.35294117647058826\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Custom Views/Upload Loading View/UploadLoadingView.swift",
    "content": "//\n//  UploadLoadingView.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 11/01/2024.\n//\n\nimport Foundation\nimport UIKit\n\nclass UploadLoadingView: UIView {\n\n    @IBOutlet weak var aiLoading: UIActivityIndicatorView!\n    override init(frame: CGRect) {\n        super.init(frame: frame)\n        commonInit()\n    }\n\n    required init?(coder aDecoder: NSCoder) {\n        super.init(coder: aDecoder)\n        commonInit()\n    }\n\n    private func commonInit() {\n        guard let view = loadViewFromNib() else { return }\n        view.frame = bounds\n        view.autoresizingMask = [.flexibleWidth, .flexibleHeight]\n        view.layer.cornerRadius = 4\n        addSubview(view)\n    }\n\n    private func loadViewFromNib() -> UIView? {\n        let nib = UINib(nibName: \"UploadLoadingView\", bundle: nil)\n        return nib.instantiate(withOwner: self, options: nil).first as? UIView\n    }\n\n    func startAnimation() {\n        aiLoading.startAnimating()\n    }\n\n    func stopAnimation() {\n        aiLoading.stopAnimating()\n    }\n\n}\n\n"
  },
  {
    "path": "Example/Cloudinary/Custom Views/Upload Loading View/UploadLoadingView.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"UploadLoadingView\" customModule=\"Cloudinary_Example\" customModuleProvider=\"target\">\n            <connections>\n                <outlet property=\"aiLoading\" destination=\"5E0-Tl-dG8\" id=\"9w3-yo-7QW\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"180\" height=\"110\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <view alpha=\"0.59999999999999998\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bvn-xy-2AX\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"180\" height=\"110\"/>\n                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                    <userDefinedRuntimeAttributes>\n                        <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                            <integer key=\"value\" value=\"4\"/>\n                        </userDefinedRuntimeAttribute>\n                    </userDefinedRuntimeAttributes>\n                </view>\n                <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1pc-7N-QhV\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"180\" height=\"110\"/>\n                    <subviews>\n                        <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eFt-Sc-jd2\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"180\" height=\"66\"/>\n                            <subviews>\n                                <activityIndicatorView opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" style=\"large\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5E0-Tl-dG8\">\n                                    <rect key=\"frame\" x=\"71.666666666666671\" y=\"29.666666666666671\" width=\"37\" height=\"37\"/>\n                                    <color key=\"color\" name=\"primary\"/>\n                                </activityIndicatorView>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                            <constraints>\n                                <constraint firstItem=\"5E0-Tl-dG8\" firstAttribute=\"centerY\" secondItem=\"eFt-Sc-jd2\" secondAttribute=\"centerY\" constant=\"15\" id=\"o4p-i4-qpq\"/>\n                                <constraint firstItem=\"5E0-Tl-dG8\" firstAttribute=\"centerX\" secondItem=\"eFt-Sc-jd2\" secondAttribute=\"centerX\" id=\"qp7-Ti-Xsk\"/>\n                            </constraints>\n                        </view>\n                        <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Enx-jL-zHh\">\n                            <rect key=\"frame\" x=\"0.0\" y=\"66\" width=\"180\" height=\"44\"/>\n                            <subviews>\n                                <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Uploading your asset...\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zo4-ZJ-OAt\">\n                                    <rect key=\"frame\" x=\"8\" y=\"12.333333333333327\" width=\"164.33333333333334\" height=\"19.333333333333329\"/>\n                                    <fontDescription key=\"fontDescription\" type=\"system\" weight=\"light\" pointSize=\"16\"/>\n                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                    <nil key=\"highlightedColor\"/>\n                                </label>\n                            </subviews>\n                            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                            <constraints>\n                                <constraint firstItem=\"zo4-ZJ-OAt\" firstAttribute=\"centerY\" secondItem=\"Enx-jL-zHh\" secondAttribute=\"centerY\" id=\"Fj0-4M-8DZ\"/>\n                                <constraint firstItem=\"zo4-ZJ-OAt\" firstAttribute=\"centerX\" secondItem=\"Enx-jL-zHh\" secondAttribute=\"centerX\" id=\"P6d-ov-QGO\"/>\n                            </constraints>\n                        </view>\n                    </subviews>\n                    <constraints>\n                        <constraint firstItem=\"eFt-Sc-jd2\" firstAttribute=\"height\" secondItem=\"1pc-7N-QhV\" secondAttribute=\"height\" multiplier=\"0.6\" id=\"DTp-6c-gGu\"/>\n                    </constraints>\n                </stackView>\n            </subviews>\n            <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n            <constraints>\n                <constraint firstItem=\"bvn-xy-2AX\" firstAttribute=\"top\" secondItem=\"iN0-l3-epB\" secondAttribute=\"top\" id=\"Ioc-AP-AXh\"/>\n                <constraint firstItem=\"1pc-7N-QhV\" firstAttribute=\"top\" secondItem=\"iN0-l3-epB\" secondAttribute=\"top\" id=\"It6-fP-6fO\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"1pc-7N-QhV\" secondAttribute=\"bottom\" id=\"KIn-pd-aKS\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"1pc-7N-QhV\" secondAttribute=\"trailing\" id=\"RRE-M2-X15\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"bvn-xy-2AX\" secondAttribute=\"trailing\" id=\"j84-0p-lRM\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"bvn-xy-2AX\" secondAttribute=\"bottom\" id=\"k8b-aY-WtP\"/>\n                <constraint firstItem=\"bvn-xy-2AX\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" id=\"tQe-Zs-j2A\"/>\n                <constraint firstItem=\"1pc-7N-QhV\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" id=\"ucY-RF-XCh\"/>\n            </constraints>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"6.1068702290076331\" y=\"200.70422535211267\"/>\n        </view>\n    </objects>\n    <resources>\n        <namedColor name=\"primary\">\n            <color red=\"0.27450980392156865\" green=\"0.59607843137254901\" blue=\"0.96862745098039216\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Extensions/Double+Extension.swift",
    "content": "//\n//  Double+Extension.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 18/09/2023.\n//\n\nimport Foundation\nextension Double {\n    /// Rounds the double to decimal places value\n    func rounded(toPlaces places:Int) -> Double {\n        let divisor = pow(10.0, Double(places))\n        return (self * divisor).rounded() / divisor\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/GoogleService-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>API_KEY</key>\n\t<string>AIzaSyCFgj2Omu6hBF7frbKT-LHQHJmXiiK2OOo</string>\n\t<key>GCM_SENDER_ID</key>\n\t<string>554013255617</string>\n\t<key>PLIST_VERSION</key>\n\t<string>1</string>\n\t<key>BUNDLE_ID</key>\n\t<string>com.cloudinary.Cloudinary-Sample-App</string>\n\t<key>PROJECT_ID</key>\n\t<string>ios-sample-app-d3d7d</string>\n\t<key>STORAGE_BUCKET</key>\n\t<string>ios-sample-app-d3d7d.appspot.com</string>\n\t<key>IS_ADS_ENABLED</key>\n\t<false></false>\n\t<key>IS_ANALYTICS_ENABLED</key>\n\t<false></false>\n\t<key>IS_APPINVITE_ENABLED</key>\n\t<true></true>\n\t<key>IS_GCM_ENABLED</key>\n\t<true></true>\n\t<key>IS_SIGNIN_ENABLED</key>\n\t<true></true>\n\t<key>GOOGLE_APP_ID</key>\n\t<string>1:554013255617:ios:8a787dcf8bc7e668ca3140</string>\n</dict>\n</plist>"
  },
  {
    "path": "Example/Cloudinary/Helpers/AnimationHelper.swift",
    "content": "//\n//  AnimationHelper.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 03/01/2024.\n//\n\nimport Foundation\nimport UIKit\nclass AnimationHelper {\n\n    public static func animateOut(view: UIView) {\n        UIView.animate(withDuration: 0.5) {\n            view.alpha = 0\n        } completion: { _ in\n            view.removeFromSuperview()\n        }\n    }\n\n    public static func animateTabController(_ vwContainer: UIView, _ newController: UIViewController, currentViewController: UIViewController?, completion: @escaping () -> Void) {\n\n        let animationDirection = getAnimationDirection(newController, currentViewController)\n        // Add new controller as child\n\n        // Add the new controller's view\n        vwContainer.addSubview(newController.view)\n\n        // Perform the animation\n        if animationDirection == .leftToRight {\n            newController.view.frame = CGRect(x: vwContainer.bounds.width, y: 0, width: vwContainer.bounds.width, height: vwContainer.bounds.height)\n            UIView.animate(withDuration: 0.5) {\n                // Slide the current view out to the left\n                if let viewController = currentViewController {\n                    viewController.view.frame.origin.x = -vwContainer.bounds.width\n                }\n\n                // Slide the new view in from the right\n                newController.view.frame.origin.x = 0\n            } completion: { (_) in\n                completion()\n            }\n        } else {\n            newController.view.frame = CGRect(x: -vwContainer.bounds.width, y: 0, width: vwContainer.bounds.width, height: vwContainer.bounds.height)\n            UIView.animate(withDuration: 0.25) {\n                if let viewController = currentViewController {\n                    viewController.view.frame.origin.x = vwContainer.bounds.width\n                }\n\n                // Slide the new view in from the left\n                newController.view.frame.origin.x = 0\n            } completion: { (_) in\n                completion()\n            }\n        }\n    }\n\n\n    private static func getAnimationDirection(_ newController: UIViewController, _ currentController: UIViewController?) -> AnimationDirection {\n        guard let currentController = currentController else {\n            return .leftToRight\n        }\n        if let _ = newController as? DeliveryViewController {\n            return .rightToLeft;\n        }\n        if let _ = newController as? UploadViewController {\n            if let _ = currentController as? DeliveryViewController {\n                return .leftToRight\n            } else {\n                return .rightToLeft\n            }\n        }\n        return .leftToRight\n    }\n\n    public static func animateTitleOut(_ view: UIView) {\n        UIView.animate(withDuration: 0.25, animations: {\n            view.alpha = 0.0\n        })\n    }\n\n    public static func animateTitleIn(_ view: UIView) {\n        UIView.animate(withDuration: 0.25, animations: {\n            view.alpha = 1.0\n        })\n    }\n\n    enum AnimationDirection {\n        case rightToLeft\n        case leftToRight\n    }\n}\n\n"
  },
  {
    "path": "Example/Cloudinary/Helpers/Events/EventObject.swift",
    "content": "//\n//  EventObject.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 05/02/2024.\n//\n\nimport Foundation\n\nclass EventObject{\n    var eventName:String?;\n    var eventAttributes:[String:String]?;\n\n    init(name: String, attributes: [String: String]? = nil) {\n        self.eventName = name\n        self.eventAttributes = attributes\n    }\n\n    func getAttributes() -> [String:String]? {\n        return eventAttributes;\n    }\n\n    func setEventAttribute(_ key:String,_ value:String) {\n        eventAttributes![key] = value;\n    }\n\n    func setEventAttributes(attrs:[String:String]) {\n        self.eventAttributes = attrs;\n    }\n\n    func getEventName()->String {\n        return eventName!;\n    }\n\n    func setEventName(name:String) {\n        eventName = name;\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Helpers/Events/EventsHandler.swift",
    "content": "//\n//  EventsHandler.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 05/02/2024.\n//\n\nimport Foundation\nimport Foundation\nclass EventsHandler{\n    static let shared = EventsHandler();\n    private var providersList = [EventsProvider]();\n    private init() {\n        initProvidersList();\n    }\n\n    private func initProvidersList(){\n        providersList.append(FirebaseEventsHandler())\n    }\n\n    func logEvent(event:EventObject){\n        for provider in providersList{\n            provider.logEvent(event: event);\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "Example/Cloudinary/Helpers/Events/EventsProvider.swift",
    "content": "//\n//  EventsProvider.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 05/02/2024.\n//\n\nimport Foundation\n\nprotocol EventsProvider {\n    func logEvent(event: EventObject)\n}\n"
  },
  {
    "path": "Example/Cloudinary/Helpers/Events/FirebaseEventsHandler.swift",
    "content": "//\n//  FirebaseEventsHandler.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 05/02/2024.\n//\n\nimport Foundation\n//import Firebase\n\nclass FirebaseEventsHandler: EventsProvider {\n    func logEvent(event: EventObject) {\n//        Analytics.logEvent(event.getEventName(), parameters: event.getAttributes())\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Helpers/ImageHelper.swift",
    "content": "//\n//  ImageHelper.swift\n//  Cloudinary_Sample_App\n//\n//  Created by Adi Mizrahi on 09/01/2024.\n//\n\nimport Foundation\nimport UIKit\nclass ImageHelper {\n    static func getImageFromURL(_ url: URL, completion: @escaping (UIImage?) -> Void) {\n        URLSession.shared.dataTask(with: url) { data, response, error in\n            guard let data = data, error == nil else {\n                completion(nil)\n                return\n            }\n\n            if let image = UIImage(data: data) {\n                completion(image)\n            } else {\n                completion(nil)\n            }\n        }.resume()\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/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>CFBundleName</key>\n\t<string>Cloudinary</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>NSPhotoLibraryUsageDescription</key>\n\t<string>The app needs access to the photo library in order for you to choose photos and videos for uploading</string>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneConfigurationName</key>\n\t\t\t\t\t<string>Default Configuration</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key>\n\t\t\t\t\t<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>\n\t\t\t\t\t<key>UISceneStoryboardFile</key>\n\t\t\t\t\t<string>Splash</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen.storyboard</string>\n\t<key>UIStatusBarStyle</key>\n\t<string></string>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Example/Cloudinary/SceneDelegate.swift",
    "content": "//\n//  SceneDelegate.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 11/09/2023.\n//\n\nimport UIKit\n\nclass SceneDelegate: UIResponder, UIWindowSceneDelegate {\n\n    var window: UIWindow?\n\n\n    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {\n        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.\n        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.\n        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).\n        guard let _ = (scene as? UIWindowScene) else { return }\n    }\n\n    func sceneDidDisconnect(_ scene: UIScene) {\n        // Called as the scene is being released by the system.\n        // This occurs shortly after the scene enters the background, or when its session is discarded.\n        // Release any resources associated with this scene that can be re-created the next time the scene connects.\n        // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).\n    }\n\n    func sceneDidBecomeActive(_ scene: UIScene) {\n        // Called when the scene has moved from an inactive state to an active state.\n        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.\n    }\n\n    func sceneWillResignActive(_ scene: UIScene) {\n        // Called when the scene will move from an active state to an inactive state.\n        // This may occur due to temporary interruptions (ex. an incoming phone call).\n    }\n\n    func sceneWillEnterForeground(_ scene: UIScene) {\n        // Called as the scene transitions from the background to the foreground.\n        // Use this method to undo the changes made on entering the background.\n    }\n\n    func sceneDidEnterBackground(_ scene: UIScene) {\n        // Called as the scene transitions from the foreground to the background.\n        // Use this method to save data, release shared resources, and store enough scene-specific state information\n        // to restore the scene back to its current state.\n    }\n\n\n}\n\n"
  },
  {
    "path": "Example/Cloudinary/Utils/CloudinaryHelper.swift",
    "content": "//\n//  CloudinaryHelper.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 12/09/2023.\n//\n\nimport Foundation\nimport Cloudinary\n\nclass CloudinaryHelper {\n    static let shared = CloudinaryHelper()\n\n    var cloudinary: CLDCloudinary\n\n    init() {\n        cloudinary = CLDCloudinary(configuration: CLDConfiguration(cloudName: \"mobiledemoapp\", secure: true))\n    }\n\n    func setUploadCloud(_ cloudName: String?) {\n        guard let cloudName = cloudName else {\n            return\n        }\n        UserDefaults.standard.set(cloudName, forKey: \"uploadCloudName\")\n    }\n\n    func getUploadCloud() -> String? {\n        guard let cloudName = UserDefaults.standard.value(forKey: \"uploadCloudName\") as? String else {\n            return nil\n        }\n        return cloudName\n    }\n}\n"
  },
  {
    "path": "Example/Cloudinary/Utils/FileUtils.swift",
    "content": "//\n//  FileUtils.swift\n//  iOS_Geekle_Conference\n//\n//  Created by Adi Mizrahi on 18/09/2023.\n//\n\nimport Foundation\nimport UIKit\nclass FileUtils {\n    static func getFileSizeForImage(_ image: UIImage) -> String {\n        guard let imgData = image.jpegData(compressionQuality: 1.0) else {\n            return \"\"\n        }\n        let imageSize: Int = imgData.count\n        let size = Double(imageSize) / 1024.0 / 1024.0\n        return \"\\(size.rounded(toPlaces: 2))\"\n    }\n\n    static func getImageInfo(_ url: URL, completion: @escaping (_ format: String, _ size: String, _ dimensions: (width: CGFloat, height: CGFloat)) -> Void) {\n        getData(from: url) { data, response, error in\n            guard let data = data, error == nil else {\n                // Handle error case\n                return\n            }\n\n            DispatchQueue.main.async {\n                guard data.count > 0 else {\n                    return\n                }\n                let format = ImageFormat.get(from: data).rawValue\n\n                let imageSize: Int = data.count\n                let size = Double(imageSize) / 1024.0 / 1024.0\n\n                let image = UIImage(data: data)\n                let dimensions = image.map { ($0.size.width, $0.size.height) }\n\n                completion(format, \"\\(size.rounded(toPlaces: 2))\", dimensions!)\n            }\n        }\n    }\n\n    private static func getData(from url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {\n        let request = URLRequest(url: url)\n        URLSession.shared.dataTask(with: request, completionHandler: completion).resume()\n    }\n}\n\nenum ImageFormat: String {\n    case png, jpg, gif, tiff, webp, heic, unknown\n}\n\nextension ImageFormat {\n    static func get(from data: Data) -> ImageFormat {\n        switch data[0] {\n        case 0x89:\n            return .png\n        case 0xFF:\n            return .jpg\n        case 0x47:\n            return .gif\n        case 0x49, 0x4D:\n            return .tiff\n        case 0x52 where data.count >= 12:\n            let subdata = data[0...11]\n\n            if let dataString = String(data: subdata, encoding: .ascii),\n               dataString.hasPrefix(\"RIFF\"),\n               dataString.hasSuffix(\"WEBP\")\n            {\n                return .webp\n            }\n\n        case 0x00 where data.count >= 12 :\n            let subdata = data[8...11]\n\n            if let dataString = String(data: subdata, encoding: .ascii),\n               Set([\"heic\", \"heix\", \"hevc\", \"hevx\"]).contains(dataString)\n            ///OLD: \"ftypheic\", \"ftypheix\", \"ftyphevc\", \"ftyphevx\"\n            {\n                return .heic\n            }\n        default:\n            break\n        }\n        return .unknown\n    }\n\n    var contentType: String {\n        return \"image/\\(rawValue)\"\n    }\n}\n\n"
  },
  {
    "path": "Example/Cloudinary/Views/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=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"splash\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"haO-1B-svC\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                            </imageView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                        <constraints>\n                            <constraint firstItem=\"haO-1B-svC\" firstAttribute=\"leading\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"leading\" id=\"V3u-rI-rQi\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"trailing\" secondItem=\"haO-1B-svC\" secondAttribute=\"trailing\" id=\"grU-hr-Hq6\"/>\n                            <constraint firstItem=\"haO-1B-svC\" firstAttribute=\"top\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"top\" constant=\"-59\" id=\"xFS-m1-gBm\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"bottom\" secondItem=\"haO-1B-svC\" secondAttribute=\"bottom\" constant=\"-34\" id=\"xlg-mN-NNg\"/>\n                        </constraints>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"52.671755725190835\" y=\"374.64788732394368\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"splash\" width=\"786\" height=\"1704\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/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=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"211-oj-NZO\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Main View Controller-->\n        <scene sceneID=\"v3y-Lx-n0X\">\n            <objects>\n                <viewController storyboardIdentifier=\"MainViewController\" id=\"211-oj-NZO\" customClass=\"MainViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ahx-fK-tlN\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <containerView opaque=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ii6-Nv-fvN\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"59\" width=\"393\" height=\"695\"/>\n                            </containerView>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZqZ-MY-IjW\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"754\" width=\"393\" height=\"98\"/>\n                                <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"98\" id=\"gSI-lK-u57\"/>\n                                </constraints>\n                            </view>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"7hI-kI-zaG\"/>\n                        <color key=\"backgroundColor\" name=\"surface\"/>\n                        <constraints>\n                            <constraint firstItem=\"ZqZ-MY-IjW\" firstAttribute=\"bottom\" secondItem=\"7hI-kI-zaG\" secondAttribute=\"bottom\" constant=\"34\" id=\"2a8-0e-bBd\"/>\n                            <constraint firstItem=\"ZqZ-MY-IjW\" firstAttribute=\"width\" secondItem=\"7hI-kI-zaG\" secondAttribute=\"width\" id=\"P0D-Cf-OFa\"/>\n                            <constraint firstItem=\"ZqZ-MY-IjW\" firstAttribute=\"centerX\" secondItem=\"7hI-kI-zaG\" secondAttribute=\"centerX\" id=\"Td9-zV-Yvd\"/>\n                            <constraint firstItem=\"ZqZ-MY-IjW\" firstAttribute=\"top\" secondItem=\"ii6-Nv-fvN\" secondAttribute=\"bottom\" id=\"Xkh-ir-kg6\"/>\n                            <constraint firstItem=\"ii6-Nv-fvN\" firstAttribute=\"top\" secondItem=\"7hI-kI-zaG\" secondAttribute=\"top\" id=\"hRE-It-HE2\"/>\n                            <constraint firstItem=\"ii6-Nv-fvN\" firstAttribute=\"leading\" secondItem=\"7hI-kI-zaG\" secondAttribute=\"leading\" id=\"kXD-Y1-KRd\"/>\n                            <constraint firstItem=\"7hI-kI-zaG\" firstAttribute=\"trailing\" secondItem=\"ii6-Nv-fvN\" secondAttribute=\"trailing\" id=\"lUc-gM-UYw\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"vwContainer\" destination=\"ii6-Nv-fvN\" id=\"j00-kC-4Hd\"/>\n                        <outlet property=\"vwToolbar\" destination=\"ZqZ-MY-IjW\" id=\"H9I-0x-VQw\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"fdF-46-6pm\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-225.19083969465649\" y=\"118.30985915492958\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <namedColor name=\"surface\">\n            <color red=\"0.12549019607843137\" green=\"0.14117647058823529\" blue=\"0.17647058823529413\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Base/Base.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Base View Controller-->\n        <scene sceneID=\"s0d-6b-0kx\">\n            <objects>\n                <viewController storyboardIdentifier=\"BaseViewController\" id=\"Y6W-OH-hqX\" customClass=\"BaseViewController\" customModule=\"Cloudinary_Example\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5EZ-qb-Rvc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dJ3-hL-5cc\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"59\" width=\"393\" height=\"759\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"orB-xw-6LU\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"60.666666666666664\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UWi-4C-ej5\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"60.666666666666664\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eYI-f1-rP1\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"55\" height=\"60.666666666666664\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kna-K0-eTs\">\n                                                                <rect key=\"frame\" x=\"24\" y=\"16.333333333333329\" width=\"28\" height=\"28\"/>\n                                                                <subviews>\n                                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"center\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"back_arrow\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XQv-cC-hxD\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"28\" height=\"28\"/>\n                                                                    </imageView>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" name=\"secondary\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"XQv-cC-hxD\" firstAttribute=\"width\" secondItem=\"kna-K0-eTs\" secondAttribute=\"width\" id=\"Fjx-Jr-pCB\"/>\n                                                                    <constraint firstItem=\"XQv-cC-hxD\" firstAttribute=\"height\" secondItem=\"kna-K0-eTs\" secondAttribute=\"height\" id=\"WMl-UC-rTq\"/>\n                                                                    <constraint firstAttribute=\"width\" secondItem=\"kna-K0-eTs\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"hFx-fG-7O6\"/>\n                                                                    <constraint firstItem=\"XQv-cC-hxD\" firstAttribute=\"centerY\" secondItem=\"kna-K0-eTs\" secondAttribute=\"centerY\" id=\"nVS-xs-GbP\"/>\n                                                                    <constraint firstItem=\"XQv-cC-hxD\" firstAttribute=\"centerX\" secondItem=\"kna-K0-eTs\" secondAttribute=\"centerX\" id=\"wwn-hK-QBu\"/>\n                                                                </constraints>\n                                                                <userDefinedRuntimeAttributes>\n                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                        <integer key=\"value\" value=\"14\"/>\n                                                                    </userDefinedRuntimeAttribute>\n                                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBounds\" value=\"YES\"/>\n                                                                </userDefinedRuntimeAttributes>\n                                                            </view>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"kna-K0-eTs\" firstAttribute=\"leading\" secondItem=\"eYI-f1-rP1\" secondAttribute=\"leading\" constant=\"24\" id=\"9wL-KF-9Pa\"/>\n                                                            <constraint firstItem=\"kna-K0-eTs\" firstAttribute=\"centerY\" secondItem=\"eYI-f1-rP1\" secondAttribute=\"centerY\" id=\"HqO-yw-dj4\"/>\n                                                            <constraint firstItem=\"kna-K0-eTs\" firstAttribute=\"width\" secondItem=\"eYI-f1-rP1\" secondAttribute=\"width\" multiplier=\"0.509091\" id=\"vV3-ul-M2z\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Txj-05-h1n\">\n                                                        <rect key=\"frame\" x=\"55\" y=\"0.0\" width=\"338\" height=\"60.666666666666664\"/>\n                                                        <subviews>\n                                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CZT-Em-hhr\">\n                                                                <rect key=\"frame\" x=\"72\" y=\"19.333333333333329\" width=\"139\" height=\"22\"/>\n                                                                <subviews>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AgQ-kY-kOT\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"114\" height=\"22\"/>\n                                                                        <subviews>\n                                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Upload Widget\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9AA-oL-0ti\">\n                                                                                <rect key=\"frame\" x=\"-4.3333333333333286\" y=\"0.33333333333334281\" width=\"122.66666666666667\" height=\"21.666666666666668\"/>\n                                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                                <nil key=\"highlightedColor\"/>\n                                                                            </label>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstItem=\"9AA-oL-0ti\" firstAttribute=\"centerX\" secondItem=\"AgQ-kY-kOT\" secondAttribute=\"centerX\" id=\"Lpf-GB-Su0\"/>\n                                                                            <constraint firstItem=\"9AA-oL-0ti\" firstAttribute=\"centerY\" secondItem=\"AgQ-kY-kOT\" secondAttribute=\"centerY\" id=\"UOm-TQ-mth\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gnT-IY-kVu\">\n                                                                        <rect key=\"frame\" x=\"122\" y=\"0.0\" width=\"17\" height=\"22\"/>\n                                                                        <subviews>\n                                                                            <imageView hidden=\"YES\" clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"info_icon\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zrN-v8-Mi6\">\n                                                                                <rect key=\"frame\" x=\"-0.66666666666665719\" y=\"2\" width=\"18.333333333333332\" height=\"18\"/>\n                                                                                <constraints>\n                                                                                    <constraint firstAttribute=\"width\" secondItem=\"zrN-v8-Mi6\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"LLk-4n-bxK\"/>\n                                                                                </constraints>\n                                                                            </imageView>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstItem=\"zrN-v8-Mi6\" firstAttribute=\"centerX\" secondItem=\"gnT-IY-kVu\" secondAttribute=\"centerX\" id=\"lVd-pf-AHV\"/>\n                                                                            <constraint firstItem=\"zrN-v8-Mi6\" firstAttribute=\"width\" secondItem=\"gnT-IY-kVu\" secondAttribute=\"width\" constant=\"1\" id=\"mI8-QZ-OGj\"/>\n                                                                            <constraint firstItem=\"zrN-v8-Mi6\" firstAttribute=\"centerY\" secondItem=\"gnT-IY-kVu\" secondAttribute=\"centerY\" id=\"w34-6Y-Ysm\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                </subviews>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"AgQ-kY-kOT\" firstAttribute=\"width\" secondItem=\"CZT-Em-hhr\" secondAttribute=\"width\" multiplier=\"0.82\" id=\"BBe-LD-F6u\"/>\n                                                                    <constraint firstAttribute=\"width\" secondItem=\"CZT-Em-hhr\" secondAttribute=\"height\" multiplier=\"139:22\" id=\"lfI-4w-Xnc\"/>\n                                                                </constraints>\n                                                            </stackView>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"eYI-f1-rP1\" firstAttribute=\"width\" secondItem=\"UWi-4C-ej5\" secondAttribute=\"width\" multiplier=\"0.14\" id=\"dzI-hT-ohc\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"UWi-4C-ej5\" firstAttribute=\"top\" secondItem=\"orB-xw-6LU\" secondAttribute=\"top\" id=\"5tK-vO-Meg\"/>\n                                            <constraint firstItem=\"CZT-Em-hhr\" firstAttribute=\"centerY\" secondItem=\"orB-xw-6LU\" secondAttribute=\"centerY\" id=\"Q2z-YW-Iaq\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"UWi-4C-ej5\" secondAttribute=\"bottom\" id=\"eW4-U3-hy5\"/>\n                                            <constraint firstItem=\"CZT-Em-hhr\" firstAttribute=\"centerX\" secondItem=\"orB-xw-6LU\" secondAttribute=\"centerX\" id=\"kUK-cu-GYP\"/>\n                                            <constraint firstItem=\"CZT-Em-hhr\" firstAttribute=\"width\" secondItem=\"orB-xw-6LU\" secondAttribute=\"width\" multiplier=\"0.35369\" id=\"tmE-p2-eI8\"/>\n                                            <constraint firstItem=\"UWi-4C-ej5\" firstAttribute=\"leading\" secondItem=\"orB-xw-6LU\" secondAttribute=\"leading\" id=\"vtc-e8-iuS\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"UWi-4C-ej5\" secondAttribute=\"trailing\" id=\"yfW-n6-9qs\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"06E-kj-VJN\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"60.666666666666686\" width=\"393\" height=\"698.33333333333326\"/>\n                                        <subviews>\n                                            <containerView opaque=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"76K-Ry-w3M\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"698.33333333333337\"/>\n                                            </containerView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"76K-Ry-w3M\" secondAttribute=\"bottom\" id=\"Ktg-oQ-DZc\"/>\n                                            <constraint firstItem=\"76K-Ry-w3M\" firstAttribute=\"top\" secondItem=\"06E-kj-VJN\" secondAttribute=\"top\" id=\"Qk0-YV-W2K\"/>\n                                            <constraint firstItem=\"76K-Ry-w3M\" firstAttribute=\"leading\" secondItem=\"06E-kj-VJN\" secondAttribute=\"leading\" id=\"azA-zu-Bv9\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"76K-Ry-w3M\" secondAttribute=\"trailing\" id=\"yhl-VO-fQk\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"orB-xw-6LU\" firstAttribute=\"height\" secondItem=\"dJ3-hL-5cc\" secondAttribute=\"height\" multiplier=\"0.08\" id=\"91x-Ww-PeF\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"vDu-zF-Fre\"/>\n                        <color key=\"backgroundColor\" name=\"surface\"/>\n                        <constraints>\n                            <constraint firstItem=\"vDu-zF-Fre\" firstAttribute=\"trailing\" secondItem=\"dJ3-hL-5cc\" secondAttribute=\"trailing\" id=\"536-KK-gMz\"/>\n                            <constraint firstItem=\"dJ3-hL-5cc\" firstAttribute=\"top\" secondItem=\"vDu-zF-Fre\" secondAttribute=\"top\" id=\"5hz-Le-H3J\"/>\n                            <constraint firstItem=\"vDu-zF-Fre\" firstAttribute=\"bottom\" secondItem=\"dJ3-hL-5cc\" secondAttribute=\"bottom\" id=\"gx8-wx-UZp\"/>\n                            <constraint firstItem=\"dJ3-hL-5cc\" firstAttribute=\"leading\" secondItem=\"vDu-zF-Fre\" secondAttribute=\"leading\" id=\"pSU-9N-PWq\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"lbTitle\" destination=\"9AA-oL-0ti\" id=\"SGY-Ns-1KY\"/>\n                        <outlet property=\"vwBack\" destination=\"eYI-f1-rP1\" id=\"zNX-ml-fj2\"/>\n                        <outlet property=\"vwContainer\" destination=\"76K-Ry-w3M\" id=\"Qjf-2b-HEG\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Ief-a0-LHa\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"72.51908396946564\" y=\"3.5211267605633805\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"back_arrow\" width=\"12\" height=\"12\"/>\n        <image name=\"info_icon\" width=\"20\" height=\"20\"/>\n        <namedColor name=\"secondary\">\n            <color red=\"0.24705882352941178\" green=\"0.27843137254901962\" blue=\"0.35294117647058826\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"surface\">\n            <color red=\"0.12549019607843137\" green=\"0.14117647058823529\" blue=\"0.17647058823529413\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Transform/Delivery.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"collection view cell content view\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Delivery View Controller-->\n        <scene sceneID=\"s0d-6b-0kx\">\n            <objects>\n                <viewController restorationIdentifier=\"DeliveryViewController\" storyboardIdentifier=\"DeliveryViewController\" id=\"Y6W-OH-hqX\" customClass=\"DeliveryViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"kv1-KA-H7H\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"job-MX-MF7\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5EZ-qb-Rvc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sQC-Yu-m81\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"59\" width=\"393\" height=\"759\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OFv-6b-QdD\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"102.33333333333333\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gzc-lH-mTZ\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"102.33333333333333\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oRb-F9-VEi\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"66.666666666666671\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Delivery\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0i7-Tt-HVG\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"11.666666666666671\" width=\"132.66666666666666\" height=\"43\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"semibold\" pointSize=\"36\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"0i7-Tt-HVG\" firstAttribute=\"leading\" secondItem=\"oRb-F9-VEi\" secondAttribute=\"leading\" constant=\"16\" id=\"DUZ-No-wwS\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"0i7-Tt-HVG\" secondAttribute=\"bottom\" constant=\"12\" id=\"qEm-w9-BS3\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"y8G-mb-7Eh\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"66.666666666666671\" width=\"393\" height=\"35.666666666666671\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bL6-FZ-1HJ\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"47\" height=\"5\"/>\n                                                                <color key=\"backgroundColor\" name=\"primary\"/>\n                                                                <constraints>\n                                                                    <constraint firstAttribute=\"height\" constant=\"5\" id=\"fvH-xD-EZZ\"/>\n                                                                </constraints>\n                                                                <userDefinedRuntimeAttributes>\n                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                        <real key=\"value\" value=\"2.5\"/>\n                                                                    </userDefinedRuntimeAttribute>\n                                                                </userDefinedRuntimeAttributes>\n                                                            </view>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"bL6-FZ-1HJ\" firstAttribute=\"top\" secondItem=\"y8G-mb-7Eh\" secondAttribute=\"top\" id=\"45p-ge-bB1\"/>\n                                                            <constraint firstItem=\"bL6-FZ-1HJ\" firstAttribute=\"width\" secondItem=\"y8G-mb-7Eh\" secondAttribute=\"width\" multiplier=\"0.119593\" id=\"BvH-eL-OQ9\"/>\n                                                            <constraint firstItem=\"bL6-FZ-1HJ\" firstAttribute=\"leading\" secondItem=\"y8G-mb-7Eh\" secondAttribute=\"leading\" constant=\"16\" id=\"uOv-16-Niy\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"oRb-F9-VEi\" firstAttribute=\"height\" secondItem=\"gzc-lH-mTZ\" secondAttribute=\"height\" multiplier=\"0.65\" id=\"qVN-2c-AYL\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"gzc-lH-mTZ\" secondAttribute=\"bottom\" id=\"7p2-Xe-QaE\"/>\n                                            <constraint firstItem=\"gzc-lH-mTZ\" firstAttribute=\"top\" secondItem=\"OFv-6b-QdD\" secondAttribute=\"top\" id=\"F1p-aH-Zgj\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"gzc-lH-mTZ\" secondAttribute=\"trailing\" id=\"FBa-y0-DGT\"/>\n                                            <constraint firstItem=\"gzc-lH-mTZ\" firstAttribute=\"leading\" secondItem=\"OFv-6b-QdD\" secondAttribute=\"leading\" id=\"etv-eg-dc0\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QOY-kV-AN1\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"102.33333333333334\" width=\"393\" height=\"70.666666666666657\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7vN-o7-8vo\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"70.666666666666671\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iXA-2E-gSn\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"30.333333333333332\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Optimization\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"DWQ-nI-twz\">\n                                                                <rect key=\"frame\" x=\"15.999999999999993\" y=\"4.3333333333333144\" width=\"105.33333333333331\" height=\"21.666666666666668\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"DWQ-nI-twz\" firstAttribute=\"centerY\" secondItem=\"iXA-2E-gSn\" secondAttribute=\"centerY\" id=\"69x-Pn-jjQ\"/>\n                                                            <constraint firstItem=\"DWQ-nI-twz\" firstAttribute=\"leading\" secondItem=\"iXA-2E-gSn\" secondAttribute=\"leading\" constant=\"16\" id=\"Zyx-Yc-bAT\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dDe-Kc-o2M\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"30.333333333333318\" width=\"393\" height=\"40.333333333333343\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Improve web and app performance\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Bmw-Aa-chy\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"10.666666666666684\" width=\"253\" height=\"19.333333333333329\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"16\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"Bmw-Aa-chy\" firstAttribute=\"leading\" secondItem=\"dDe-Kc-o2M\" secondAttribute=\"leading\" constant=\"16\" id=\"1Il-Ov-GNi\"/>\n                                                            <constraint firstItem=\"Bmw-Aa-chy\" firstAttribute=\"centerY\" secondItem=\"dDe-Kc-o2M\" secondAttribute=\"centerY\" id=\"Lhl-KP-yCI\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"iXA-2E-gSn\" firstAttribute=\"height\" secondItem=\"7vN-o7-8vo\" secondAttribute=\"height\" multiplier=\"0.43\" id=\"N0d-St-NPn\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"7vN-o7-8vo\" secondAttribute=\"trailing\" id=\"2tC-4x-g8j\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"7vN-o7-8vo\" secondAttribute=\"bottom\" id=\"UQO-DT-jxl\"/>\n                                            <constraint firstItem=\"7vN-o7-8vo\" firstAttribute=\"top\" secondItem=\"QOY-kV-AN1\" secondAttribute=\"top\" id=\"Wx0-TR-eKX\"/>\n                                            <constraint firstItem=\"7vN-o7-8vo\" firstAttribute=\"leading\" secondItem=\"QOY-kV-AN1\" secondAttribute=\"leading\" id=\"ZL4-y2-B2I\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iJZ-7O-nTt\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"173\" width=\"393\" height=\"189.66666666666663\"/>\n                                        <subviews>\n                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"delivery-city\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"e4l-wg-9RZ\">\n                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"361\" height=\"164.66666666666666\"/>\n                                                <userDefinedRuntimeAttributes>\n                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                        <integer key=\"value\" value=\"4\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                </userDefinedRuntimeAttributes>\n                                            </imageView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"e4l-wg-9RZ\" secondAttribute=\"trailing\" constant=\"16\" id=\"7P0-o3-AyQ\"/>\n                                            <constraint firstItem=\"e4l-wg-9RZ\" firstAttribute=\"leading\" secondItem=\"iJZ-7O-nTt\" secondAttribute=\"leading\" constant=\"16\" id=\"cch-93-xQX\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"e4l-wg-9RZ\" secondAttribute=\"bottom\" constant=\"25\" id=\"mBS-KQ-aRF\"/>\n                                            <constraint firstItem=\"e4l-wg-9RZ\" firstAttribute=\"top\" secondItem=\"iJZ-7O-nTt\" secondAttribute=\"top\" id=\"qCV-7j-tjb\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Uc0-XM-8T5\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"362.66666666666669\" width=\"393\" height=\"38\"/>\n                                        <subviews>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Trasnformation\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ENP-j3-REa\">\n                                                <rect key=\"frame\" x=\"16.000000000000007\" y=\"8.3333333333333162\" width=\"125.66666666666669\" height=\"21.666666666666671\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"ENP-j3-REa\" firstAttribute=\"centerY\" secondItem=\"Uc0-XM-8T5\" secondAttribute=\"centerY\" id=\"AOb-Qp-x44\"/>\n                                            <constraint firstItem=\"ENP-j3-REa\" firstAttribute=\"leading\" secondItem=\"Uc0-XM-8T5\" secondAttribute=\"leading\" constant=\"16\" id=\"sGY-Nz-Tlc\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sdC-3c-nwB\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"400.66666666666669\" width=\"393\" height=\"159.33333333333331\"/>\n                                        <subviews>\n                                            <collectionView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" dataMode=\"prototypes\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PPF-c8-QXB\">\n                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"377\" height=\"159.33333333333334\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <collectionViewFlowLayout key=\"collectionViewLayout\" scrollDirection=\"horizontal\" minimumLineSpacing=\"10\" minimumInteritemSpacing=\"10\" id=\"ITk-Nq-vko\">\n                                                    <size key=\"itemSize\" width=\"224\" height=\"135\"/>\n                                                    <size key=\"headerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <size key=\"footerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <inset key=\"sectionInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                                </collectionViewFlowLayout>\n                                                <cells>\n                                                    <collectionViewCell opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" reuseIdentifier=\"transfromationCell\" id=\"AoN-er-D9K\" customClass=\"TransformationCell\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"12.333333333333334\" width=\"224\" height=\"135\"/>\n                                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                        <collectionViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"aD9-zf-AUz\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"224\" height=\"135\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                                            <subviews>\n                                                                <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"delivery-smart_crop\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MM1-Mu-KKt\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"224\" height=\"135\"/>\n                                                                    <userDefinedRuntimeAttributes>\n                                                                        <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                            <integer key=\"value\" value=\"8\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                    </userDefinedRuntimeAttributes>\n                                                                </imageView>\n                                                                <view alpha=\"0.5\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bNs-0f-32A\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"224\" height=\"135\"/>\n                                                                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                    <userDefinedRuntimeAttributes>\n                                                                        <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                            <integer key=\"value\" value=\"8\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                    </userDefinedRuntimeAttributes>\n                                                                </view>\n                                                                <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Smart Cropping\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rK2-tL-amq\">\n                                                                    <rect key=\"frame\" x=\"58.666666666666657\" y=\"48.333333333333329\" width=\"107\" height=\"38.333333333333329\"/>\n                                                                    <constraints>\n                                                                        <constraint firstAttribute=\"width\" constant=\"107\" id=\"WtU-Yf-W1h\"/>\n                                                                    </constraints>\n                                                                    <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"16\"/>\n                                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                    <nil key=\"highlightedColor\"/>\n                                                                </label>\n                                                            </subviews>\n                                                            <constraints>\n                                                                <constraint firstAttribute=\"bottom\" secondItem=\"MM1-Mu-KKt\" secondAttribute=\"bottom\" id=\"1dn-0q-ZLk\"/>\n                                                                <constraint firstItem=\"bNs-0f-32A\" firstAttribute=\"leading\" secondItem=\"aD9-zf-AUz\" secondAttribute=\"leading\" id=\"5cd-wO-o61\"/>\n                                                                <constraint firstAttribute=\"trailing\" secondItem=\"MM1-Mu-KKt\" secondAttribute=\"trailing\" id=\"7FY-k0-7ET\"/>\n                                                                <constraint firstAttribute=\"bottom\" secondItem=\"bNs-0f-32A\" secondAttribute=\"bottom\" id=\"QNx-Pq-zLg\"/>\n                                                                <constraint firstItem=\"rK2-tL-amq\" firstAttribute=\"centerX\" secondItem=\"MM1-Mu-KKt\" secondAttribute=\"centerX\" id=\"S4F-Yj-YfZ\"/>\n                                                                <constraint firstItem=\"rK2-tL-amq\" firstAttribute=\"centerY\" secondItem=\"MM1-Mu-KKt\" secondAttribute=\"centerY\" id=\"SDI-Fi-BhO\"/>\n                                                                <constraint firstItem=\"MM1-Mu-KKt\" firstAttribute=\"leading\" secondItem=\"aD9-zf-AUz\" secondAttribute=\"leading\" id=\"VbV-Xo-zI9\"/>\n                                                                <constraint firstItem=\"MM1-Mu-KKt\" firstAttribute=\"top\" secondItem=\"aD9-zf-AUz\" secondAttribute=\"top\" id=\"bAE-0d-5c8\"/>\n                                                                <constraint firstAttribute=\"trailing\" secondItem=\"bNs-0f-32A\" secondAttribute=\"trailing\" id=\"cdh-PY-q0d\"/>\n                                                                <constraint firstItem=\"bNs-0f-32A\" firstAttribute=\"top\" secondItem=\"aD9-zf-AUz\" secondAttribute=\"top\" id=\"fgM-D5-X1A\"/>\n                                                            </constraints>\n                                                        </collectionViewCellContentView>\n                                                        <size key=\"customSize\" width=\"224\" height=\"135\"/>\n                                                        <connections>\n                                                            <outlet property=\"ivMain\" destination=\"MM1-Mu-KKt\" id=\"6oF-0S-pzw\"/>\n                                                            <outlet property=\"lbMain\" destination=\"rK2-tL-amq\" id=\"dDj-Ce-gbt\"/>\n                                                        </connections>\n                                                    </collectionViewCell>\n                                                </cells>\n                                            </collectionView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"PPF-c8-QXB\" firstAttribute=\"top\" secondItem=\"sdC-3c-nwB\" secondAttribute=\"top\" id=\"29K-8r-E14\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"PPF-c8-QXB\" secondAttribute=\"trailing\" id=\"5I8-L7-Lh6\"/>\n                                            <constraint firstItem=\"PPF-c8-QXB\" firstAttribute=\"leading\" secondItem=\"sdC-3c-nwB\" secondAttribute=\"leading\" constant=\"16\" id=\"RKW-G5-b59\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"PPF-c8-QXB\" secondAttribute=\"bottom\" id=\"qSt-9Z-9cc\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UiS-8w-R0p\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"560\" width=\"393\" height=\"38\"/>\n                                        <subviews>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Use cases\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LV9-6k-40U\">\n                                                <rect key=\"frame\" x=\"16\" y=\"8.333333333333373\" width=\"84.666666666666671\" height=\"21.666666666666671\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"LV9-6k-40U\" firstAttribute=\"leading\" secondItem=\"UiS-8w-R0p\" secondAttribute=\"leading\" constant=\"16\" id=\"KRV-T7-AUE\"/>\n                                            <constraint firstItem=\"LV9-6k-40U\" firstAttribute=\"centerY\" secondItem=\"UiS-8w-R0p\" secondAttribute=\"centerY\" id=\"mRP-d1-dyQ\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lof-5F-5nm\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"598\" width=\"393\" height=\"161\"/>\n                                        <subviews>\n                                            <collectionView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" dataMode=\"prototypes\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"DnZ-Ta-hfF\">\n                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"377\" height=\"161\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <collectionViewFlowLayout key=\"collectionViewLayout\" scrollDirection=\"horizontal\" minimumLineSpacing=\"10\" minimumInteritemSpacing=\"10\" id=\"Da2-PV-naC\">\n                                                    <size key=\"itemSize\" width=\"224\" height=\"135\"/>\n                                                    <size key=\"headerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <size key=\"footerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <inset key=\"sectionInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                                </collectionViewFlowLayout>\n                                                <cells>\n                                                    <collectionViewCell opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" reuseIdentifier=\"useCaseCell\" id=\"bPE-ap-JYP\" customClass=\"UseCaseCell\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"13\" width=\"224\" height=\"135\"/>\n                                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                        <collectionViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"WTh-TT-FuF\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"224\" height=\"135\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                            <subviews>\n                                                                <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kyW-ni-Cp9\" customClass=\"GradientView\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"224\" height=\"135\"/>\n                                                                    <subviews>\n                                                                        <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Normalizing Product Assets - Sizing\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jo7-3A-MdZ\">\n                                                                            <rect key=\"frame\" x=\"30\" y=\"48.333333333333329\" width=\"164\" height=\"38.333333333333329\"/>\n                                                                            <fontDescription key=\"fontDescription\" type=\"system\" weight=\"semibold\" pointSize=\"16\"/>\n                                                                            <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                            <nil key=\"highlightedColor\"/>\n                                                                        </label>\n                                                                    </subviews>\n                                                                    <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                                                                    <constraints>\n                                                                        <constraint firstItem=\"jo7-3A-MdZ\" firstAttribute=\"centerY\" secondItem=\"kyW-ni-Cp9\" secondAttribute=\"centerY\" id=\"FNw-Ul-ud8\"/>\n                                                                        <constraint firstItem=\"jo7-3A-MdZ\" firstAttribute=\"leading\" secondItem=\"kyW-ni-Cp9\" secondAttribute=\"leading\" constant=\"30\" id=\"TJA-PB-A9v\"/>\n                                                                        <constraint firstItem=\"jo7-3A-MdZ\" firstAttribute=\"centerX\" secondItem=\"kyW-ni-Cp9\" secondAttribute=\"centerX\" id=\"oSp-Tp-lDi\"/>\n                                                                    </constraints>\n                                                                    <userDefinedRuntimeAttributes>\n                                                                        <userDefinedRuntimeAttribute type=\"color\" keyPath=\"firstColor\">\n                                                                            <color key=\"value\" name=\"gradient-first\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"color\" keyPath=\"secondColor\">\n                                                                            <color key=\"value\" name=\"gradient-second\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                            <integer key=\"value\" value=\"8\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                    </userDefinedRuntimeAttributes>\n                                                                </view>\n                                                            </subviews>\n                                                            <constraints>\n                                                                <constraint firstItem=\"kyW-ni-Cp9\" firstAttribute=\"leading\" secondItem=\"WTh-TT-FuF\" secondAttribute=\"leading\" id=\"2Eu-tQ-Ibs\"/>\n                                                                <constraint firstAttribute=\"trailing\" secondItem=\"kyW-ni-Cp9\" secondAttribute=\"trailing\" id=\"G9U-xM-Gtn\"/>\n                                                                <constraint firstItem=\"kyW-ni-Cp9\" firstAttribute=\"top\" secondItem=\"WTh-TT-FuF\" secondAttribute=\"top\" id=\"kou-aX-bO1\"/>\n                                                                <constraint firstAttribute=\"bottom\" secondItem=\"kyW-ni-Cp9\" secondAttribute=\"bottom\" id=\"o9Q-t8-OnR\"/>\n                                                            </constraints>\n                                                        </collectionViewCellContentView>\n                                                        <connections>\n                                                            <outlet property=\"lbMain\" destination=\"jo7-3A-MdZ\" id=\"CoF-tl-DSL\"/>\n                                                            <outlet property=\"vwGradient\" destination=\"kyW-ni-Cp9\" id=\"Mcr-S4-dTq\"/>\n                                                        </connections>\n                                                    </collectionViewCell>\n                                                </cells>\n                                            </collectionView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"DnZ-Ta-hfF\" secondAttribute=\"trailing\" id=\"4tx-3y-IqZ\"/>\n                                            <constraint firstItem=\"DnZ-Ta-hfF\" firstAttribute=\"top\" secondItem=\"lof-5F-5nm\" secondAttribute=\"top\" id=\"YUu-OE-9KT\"/>\n                                            <constraint firstItem=\"DnZ-Ta-hfF\" firstAttribute=\"leading\" secondItem=\"lof-5F-5nm\" secondAttribute=\"leading\" constant=\"16\" id=\"jRU-Fv-Jb9\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"DnZ-Ta-hfF\" secondAttribute=\"bottom\" id=\"nVD-UP-HK3\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"Uc0-XM-8T5\" firstAttribute=\"height\" secondItem=\"sQC-Yu-m81\" secondAttribute=\"height\" multiplier=\"0.05\" id=\"Wr8-eQ-dAA\"/>\n                                    <constraint firstItem=\"QOY-kV-AN1\" firstAttribute=\"height\" secondItem=\"sQC-Yu-m81\" secondAttribute=\"height\" multiplier=\"0.093\" id=\"Zcs-Jc-OQY\"/>\n                                    <constraint firstItem=\"UiS-8w-R0p\" firstAttribute=\"height\" secondItem=\"sQC-Yu-m81\" secondAttribute=\"height\" multiplier=\"0.05\" id=\"cBH-rt-tUN\"/>\n                                    <constraint firstItem=\"iJZ-7O-nTt\" firstAttribute=\"height\" secondItem=\"sQC-Yu-m81\" secondAttribute=\"height\" multiplier=\"0.25\" id=\"er8-0F-men\"/>\n                                    <constraint firstItem=\"sdC-3c-nwB\" firstAttribute=\"height\" secondItem=\"sQC-Yu-m81\" secondAttribute=\"height\" multiplier=\"0.21\" id=\"iqd-g2-eAa\"/>\n                                    <constraint firstItem=\"OFv-6b-QdD\" firstAttribute=\"height\" secondItem=\"sQC-Yu-m81\" secondAttribute=\"height\" multiplier=\"0.135\" id=\"pom-CW-WEH\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <color key=\"backgroundColor\" name=\"surface\"/>\n                        <constraints>\n                            <constraint firstItem=\"sQC-Yu-m81\" firstAttribute=\"top\" secondItem=\"kv1-KA-H7H\" secondAttribute=\"bottom\" id=\"56Q-id-Xys\"/>\n                            <constraint firstItem=\"job-MX-MF7\" firstAttribute=\"top\" secondItem=\"sQC-Yu-m81\" secondAttribute=\"bottom\" id=\"Lyp-T8-V3t\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"sQC-Yu-m81\" secondAttribute=\"trailing\" id=\"VBR-JA-9vO\"/>\n                            <constraint firstItem=\"sQC-Yu-m81\" firstAttribute=\"leading\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"leading\" id=\"WUM-Km-ge5\"/>\n                        </constraints>\n                    </view>\n                    <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n                    <connections>\n                        <outlet property=\"cvTransformation\" destination=\"PPF-c8-QXB\" id=\"Ual-c2-XiQ\"/>\n                        <outlet property=\"cvUseCases\" destination=\"DnZ-Ta-hfF\" id=\"ewV-uN-FQ2\"/>\n                        <outlet property=\"lbTitle\" destination=\"0i7-Tt-HVG\" id=\"yvf-8Y-l0N\"/>\n                        <outlet property=\"vwOptimization\" destination=\"iJZ-7O-nTt\" id=\"6b0-OK-Z0z\"/>\n                        <outlet property=\"vwTransform\" destination=\"sdC-3c-nwB\" id=\"doi-be-kXw\"/>\n                        <outlet property=\"vwUseCases\" destination=\"lof-5F-5nm\" id=\"sQK-af-XJN\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Ief-a0-LHa\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"6\" y=\"-2\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"delivery-city\" width=\"714\" height=\"370\"/>\n        <image name=\"delivery-smart_crop\" width=\"224\" height=\"135\"/>\n        <namedColor name=\"gradient-first\">\n            <color red=\"0.20392156862745098\" green=\"0.28235294117647058\" blue=\"0.77254901960784317\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"gradient-second\">\n            <color red=\"0.15686274509803921\" green=\"0.73333333333333328\" blue=\"0.98039215686274506\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"primary\">\n            <color red=\"0.27450980392156865\" green=\"0.59607843137254901\" blue=\"0.96862745098039216\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"surface\">\n            <color red=\"0.12549019607843137\" green=\"0.14117647058823529\" blue=\"0.17647058823529413\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Transform/Optimization.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Optimization View Controller-->\n        <scene sceneID=\"20U-86-zvV\">\n            <objects>\n                <viewController storyboardIdentifier=\"OptimizationViewController\" id=\"7xg-AL-LM5\" customClass=\"OptimizationViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"fpm-Zw-1RE\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"9ln-xM-xbg\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"wHC-NQ-FDi\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" distribution=\"fillEqually\" spacing=\"10\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uSo-gm-cem\">\n                                <rect key=\"frame\" x=\"16\" y=\"59\" width=\"361\" height=\"761\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lUg-48-Jxa\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"375.66666666666669\"/>\n                                        <subviews>\n                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZXR-qt-5v3\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"375.66666666666669\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                            </imageView>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GFO-eV-JKE\">\n                                                <rect key=\"frame\" x=\"20\" y=\"305.66666666666669\" width=\"183\" height=\"50\"/>\n                                                <subviews>\n                                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rmI-k8-vjh\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"183\" height=\"50\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PnD-oD-W44\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"183\" height=\"11\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Original\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"04y-oY-tj8\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"-5.3333333333333712\" width=\"67.333333333333329\" height=\"21.666666666666668\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"18\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"04y-oY-tj8\" firstAttribute=\"centerY\" secondItem=\"PnD-oD-W44\" secondAttribute=\"centerY\" id=\"06j-3d-6c9\"/>\n                                                                    <constraint firstItem=\"04y-oY-tj8\" firstAttribute=\"leading\" secondItem=\"PnD-oD-W44\" secondAttribute=\"leading\" id=\"iWH-D7-6PU\"/>\n                                                                </constraints>\n                                                            </view>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Wr3-1a-cxi\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"11\" width=\"183\" height=\"39\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"JPG ⏺\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mG2-jV-kB5\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"11\" width=\"51\" height=\"17\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"14\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"2500x1667 ⏺\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2Zr-JX-ggT\">\n                                                                        <rect key=\"frame\" x=\"61\" y=\"11\" width=\"99\" height=\"17\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"14\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"886 KB\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iua-7p-AMO\">\n                                                                        <rect key=\"frame\" x=\"170\" y=\"11\" width=\"49.666666666666657\" height=\"17\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"14\"/>\n                                                                        <color key=\"textColor\" name=\"size_red\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"iua-7p-AMO\" firstAttribute=\"centerY\" secondItem=\"2Zr-JX-ggT\" secondAttribute=\"centerY\" id=\"AET-rz-feU\"/>\n                                                                    <constraint firstItem=\"iua-7p-AMO\" firstAttribute=\"leading\" secondItem=\"2Zr-JX-ggT\" secondAttribute=\"trailing\" constant=\"10\" id=\"Fhv-Xv-M0R\"/>\n                                                                    <constraint firstItem=\"2Zr-JX-ggT\" firstAttribute=\"centerY\" secondItem=\"mG2-jV-kB5\" secondAttribute=\"centerY\" id=\"Tn2-Sw-vnh\"/>\n                                                                    <constraint firstItem=\"mG2-jV-kB5\" firstAttribute=\"centerY\" secondItem=\"Wr3-1a-cxi\" secondAttribute=\"centerY\" id=\"W01-zO-gOO\"/>\n                                                                    <constraint firstItem=\"mG2-jV-kB5\" firstAttribute=\"leading\" secondItem=\"Wr3-1a-cxi\" secondAttribute=\"leading\" id=\"Yyj-aG-eDe\"/>\n                                                                    <constraint firstItem=\"2Zr-JX-ggT\" firstAttribute=\"leading\" secondItem=\"mG2-jV-kB5\" secondAttribute=\"trailing\" constant=\"10\" id=\"mJe-f0-i2H\"/>\n                                                                </constraints>\n                                                            </view>\n                                                        </subviews>\n                                                        <constraints>\n                                                            <constraint firstItem=\"PnD-oD-W44\" firstAttribute=\"height\" secondItem=\"rmI-k8-vjh\" secondAttribute=\"height\" multiplier=\"0.22\" id=\"2BH-cn-89Y\"/>\n                                                        </constraints>\n                                                    </stackView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"rmI-k8-vjh\" firstAttribute=\"leading\" secondItem=\"GFO-eV-JKE\" secondAttribute=\"leading\" id=\"1Zs-9z-JoG\"/>\n                                                    <constraint firstAttribute=\"width\" secondItem=\"GFO-eV-JKE\" secondAttribute=\"height\" multiplier=\"183:50\" id=\"61y-rd-N1U\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"rmI-k8-vjh\" secondAttribute=\"bottom\" id=\"P5q-fo-4bT\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"rmI-k8-vjh\" secondAttribute=\"trailing\" id=\"luK-tc-wAy\"/>\n                                                    <constraint firstItem=\"rmI-k8-vjh\" firstAttribute=\"top\" secondItem=\"GFO-eV-JKE\" secondAttribute=\"top\" id=\"wdM-1v-xDQ\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"GFO-eV-JKE\" firstAttribute=\"width\" secondItem=\"ZXR-qt-5v3\" secondAttribute=\"width\" multiplier=\"0.506925\" id=\"A0T-C8-5w0\"/>\n                                            <constraint firstItem=\"ZXR-qt-5v3\" firstAttribute=\"leading\" secondItem=\"lUg-48-Jxa\" secondAttribute=\"leading\" id=\"DcQ-BN-t7J\"/>\n                                            <constraint firstItem=\"GFO-eV-JKE\" firstAttribute=\"leading\" secondItem=\"ZXR-qt-5v3\" secondAttribute=\"leading\" constant=\"20\" id=\"WJU-Rk-F5d\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"ZXR-qt-5v3\" secondAttribute=\"bottom\" id=\"dfb-wR-i5j\"/>\n                                            <constraint firstItem=\"ZXR-qt-5v3\" firstAttribute=\"top\" secondItem=\"lUg-48-Jxa\" secondAttribute=\"top\" id=\"eae-Nd-EYe\"/>\n                                            <constraint firstItem=\"GFO-eV-JKE\" firstAttribute=\"bottom\" secondItem=\"ZXR-qt-5v3\" secondAttribute=\"bottom\" constant=\"-20\" id=\"lpg-VF-r93\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"ZXR-qt-5v3\" secondAttribute=\"trailing\" id=\"qMC-A6-jth\"/>\n                                        </constraints>\n                                        <userDefinedRuntimeAttributes>\n                                            <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                <integer key=\"value\" value=\"4\"/>\n                                            </userDefinedRuntimeAttribute>\n                                            <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBounds\" value=\"YES\"/>\n                                        </userDefinedRuntimeAttributes>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Fvr-Ge-ofj\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"385.66666666666674\" width=\"361\" height=\"375.33333333333326\"/>\n                                        <subviews>\n                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UiH-Qv-Lap\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"375.33333333333331\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                            </imageView>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KIo-sc-d6Y\">\n                                                <rect key=\"frame\" x=\"20\" y=\"305.33333333333331\" width=\"183\" height=\"50\"/>\n                                                <subviews>\n                                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8pH-lo-rLz\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"183\" height=\"50\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"obS-WC-AAR\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"183\" height=\"11\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Optimized\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UiK-6P-giD\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"-5.3333333333333712\" width=\"88.666666666666671\" height=\"21.666666666666668\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"18\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"UiK-6P-giD\" firstAttribute=\"centerY\" secondItem=\"obS-WC-AAR\" secondAttribute=\"centerY\" id=\"TBx-1R-Xcl\"/>\n                                                                    <constraint firstItem=\"UiK-6P-giD\" firstAttribute=\"leading\" secondItem=\"obS-WC-AAR\" secondAttribute=\"leading\" id=\"gF5-CK-rLD\"/>\n                                                                </constraints>\n                                                            </view>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Gzq-ff-He0\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"11\" width=\"183\" height=\"39\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"HEIC\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UmZ-9c-bGn\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"11\" width=\"32.666666666666664\" height=\"17\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"14\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"2500x1667\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"k2I-2L-Eam\">\n                                                                        <rect key=\"frame\" x=\"42.666666666666679\" y=\"11\" width=\"75.333333333333314\" height=\"17\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"14\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"262 KB\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gyG-sy-Njm\">\n                                                                        <rect key=\"frame\" x=\"127.99999999999999\" y=\"11\" width=\"48.333333333333329\" height=\"17\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"14\"/>\n                                                                        <color key=\"textColor\" name=\"size_green\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"UmZ-9c-bGn\" firstAttribute=\"centerY\" secondItem=\"Gzq-ff-He0\" secondAttribute=\"centerY\" id=\"3Ln-Hk-yoX\"/>\n                                                                    <constraint firstItem=\"UmZ-9c-bGn\" firstAttribute=\"leading\" secondItem=\"Gzq-ff-He0\" secondAttribute=\"leading\" id=\"3Us-mp-yos\"/>\n                                                                    <constraint firstItem=\"gyG-sy-Njm\" firstAttribute=\"centerY\" secondItem=\"k2I-2L-Eam\" secondAttribute=\"centerY\" id=\"8U5-0j-KWn\"/>\n                                                                    <constraint firstItem=\"gyG-sy-Njm\" firstAttribute=\"leading\" secondItem=\"k2I-2L-Eam\" secondAttribute=\"trailing\" constant=\"10\" id=\"Qwm-Sl-0D8\"/>\n                                                                    <constraint firstItem=\"k2I-2L-Eam\" firstAttribute=\"leading\" secondItem=\"UmZ-9c-bGn\" secondAttribute=\"trailing\" constant=\"10\" id=\"UHT-9Y-yy9\"/>\n                                                                    <constraint firstItem=\"k2I-2L-Eam\" firstAttribute=\"centerY\" secondItem=\"UmZ-9c-bGn\" secondAttribute=\"centerY\" id=\"n6e-Fs-VSZ\"/>\n                                                                </constraints>\n                                                            </view>\n                                                        </subviews>\n                                                        <constraints>\n                                                            <constraint firstItem=\"obS-WC-AAR\" firstAttribute=\"height\" secondItem=\"8pH-lo-rLz\" secondAttribute=\"height\" multiplier=\"0.22\" id=\"2L2-L8-qEk\"/>\n                                                        </constraints>\n                                                    </stackView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"8pH-lo-rLz\" firstAttribute=\"top\" secondItem=\"KIo-sc-d6Y\" secondAttribute=\"top\" id=\"39B-zX-5Q6\"/>\n                                                    <constraint firstItem=\"8pH-lo-rLz\" firstAttribute=\"leading\" secondItem=\"KIo-sc-d6Y\" secondAttribute=\"leading\" id=\"Iq1-If-3ut\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"8pH-lo-rLz\" secondAttribute=\"trailing\" id=\"h0i-qW-lE9\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"8pH-lo-rLz\" secondAttribute=\"bottom\" id=\"kav-Qy-AIo\"/>\n                                                    <constraint firstAttribute=\"width\" secondItem=\"KIo-sc-d6Y\" secondAttribute=\"height\" multiplier=\"183:50\" id=\"nS0-LE-gIR\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"UiH-Qv-Lap\" firstAttribute=\"top\" secondItem=\"Fvr-Ge-ofj\" secondAttribute=\"top\" id=\"2Lf-0t-pGg\"/>\n                                            <constraint firstItem=\"KIo-sc-d6Y\" firstAttribute=\"bottom\" secondItem=\"UiH-Qv-Lap\" secondAttribute=\"bottom\" constant=\"-20\" id=\"4y6-hx-Vui\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"UiH-Qv-Lap\" secondAttribute=\"bottom\" id=\"UMN-hT-y1C\"/>\n                                            <constraint firstItem=\"UiH-Qv-Lap\" firstAttribute=\"leading\" secondItem=\"Fvr-Ge-ofj\" secondAttribute=\"leading\" id=\"bTs-cz-sKy\"/>\n                                            <constraint firstItem=\"KIo-sc-d6Y\" firstAttribute=\"leading\" secondItem=\"UiH-Qv-Lap\" secondAttribute=\"leading\" constant=\"20\" id=\"dp2-UD-DdY\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"UiH-Qv-Lap\" secondAttribute=\"trailing\" id=\"qYe-E7-6E4\"/>\n                                            <constraint firstItem=\"KIo-sc-d6Y\" firstAttribute=\"width\" secondItem=\"UiH-Qv-Lap\" secondAttribute=\"width\" multiplier=\"0.506925\" id=\"qc0-RA-zH1\"/>\n                                        </constraints>\n                                        <userDefinedRuntimeAttributes>\n                                            <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                <integer key=\"value\" value=\"4\"/>\n                                            </userDefinedRuntimeAttribute>\n                                            <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBounds\" value=\"YES\"/>\n                                        </userDefinedRuntimeAttributes>\n                                    </view>\n                                </subviews>\n                            </stackView>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"uSo-gm-cem\" firstAttribute=\"top\" secondItem=\"fpm-Zw-1RE\" secondAttribute=\"bottom\" id=\"5TH-0Z-qIV\"/>\n                            <constraint firstItem=\"uSo-gm-cem\" firstAttribute=\"leading\" secondItem=\"wHC-NQ-FDi\" secondAttribute=\"leading\" constant=\"16\" id=\"Omf-kI-fGw\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"uSo-gm-cem\" secondAttribute=\"trailing\" constant=\"16\" id=\"hZn-ox-C2X\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"uSo-gm-cem\" secondAttribute=\"bottom\" constant=\"32\" id=\"m77-xx-heM\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"ivOptimized\" destination=\"UiH-Qv-Lap\" id=\"gOy-vn-ycz\"/>\n                        <outlet property=\"ivOriginal\" destination=\"ZXR-qt-5v3\" id=\"D1X-sE-Ku8\"/>\n                        <outlet property=\"lbOptimizedDimensions\" destination=\"k2I-2L-Eam\" id=\"Ubl-aq-hwd\"/>\n                        <outlet property=\"lbOptimizedFormat\" destination=\"UmZ-9c-bGn\" id=\"fsf-vr-igM\"/>\n                        <outlet property=\"lbOptimizedSize\" destination=\"gyG-sy-Njm\" id=\"28Q-oK-5B9\"/>\n                        <outlet property=\"lbOriginalDimensions\" destination=\"2Zr-JX-ggT\" id=\"vqB-jW-oVd\"/>\n                        <outlet property=\"lbOriginalFormat\" destination=\"mG2-jV-kB5\" id=\"cjr-oY-gNp\"/>\n                        <outlet property=\"lbOriginalSize\" destination=\"iua-7p-AMO\" id=\"xxk-Ct-P45\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"HhN-RK-VT5\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"129.00763358778624\" y=\"-2.1126760563380285\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <namedColor name=\"size_green\">\n            <color red=\"0.69803921568627447\" green=\"0.9882352941176471\" blue=\"0.68235294117647061\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"size_red\">\n            <color red=\"1\" green=\"0.34901960784313724\" blue=\"0.34901960784313724\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Transform/Use Cases/ConditionalProduct.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Conditional Product View Controller-->\n        <scene sceneID=\"eNU-0F-tdO\">\n            <objects>\n                <viewController storyboardIdentifier=\"ConditionalProductViewController\" id=\"ddf-Zv-ZeD\" customClass=\"ConditionalProductViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"0Vd-W3-apB\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"92N-zT-sqV\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"BzT-pS-vbj\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"603\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"G6N-zZ-vdR\">\n                                <rect key=\"frame\" x=\"16\" y=\"59\" width=\"361\" height=\"510\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M4e-im-M7y\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"183.66666666666666\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FVl-Py-pJY\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"183.66666666666666\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ibm-Wb-X2B\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"94\" height=\"183.66666666666666\"/>\n                                                        <subviews>\n                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IGL-bJ-eTT\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                                <rect key=\"frame\" x=\"5\" y=\"50.000000000000007\" width=\"83.666666666666671\" height=\"83.666666666666686\"/>\n                                                                <constraints>\n                                                                    <constraint firstAttribute=\"width\" secondItem=\"IGL-bJ-eTT\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"Tp3-Sb-K85\"/>\n                                                                </constraints>\n                                                            </imageView>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"IGL-bJ-eTT\" firstAttribute=\"centerX\" secondItem=\"Ibm-Wb-X2B\" secondAttribute=\"centerX\" id=\"0xF-Ap-KeZ\"/>\n                                                            <constraint firstItem=\"IGL-bJ-eTT\" firstAttribute=\"centerY\" secondItem=\"Ibm-Wb-X2B\" secondAttribute=\"centerY\" id=\"6ms-9y-fxy\"/>\n                                                            <constraint firstItem=\"IGL-bJ-eTT\" firstAttribute=\"width\" secondItem=\"Ibm-Wb-X2B\" secondAttribute=\"width\" multiplier=\"0.89\" id=\"YJP-8E-EPo\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eKV-1F-FoQ\">\n                                                        <rect key=\"frame\" x=\"94\" y=\"0.0\" width=\"83\" height=\"183.66666666666666\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"+\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bDx-dH-qxB\">\n                                                                <rect key=\"frame\" x=\"22\" y=\"53.333333333333321\" width=\"39\" height=\"76.666666666666686\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"64\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"bDx-dH-qxB\" firstAttribute=\"centerY\" secondItem=\"eKV-1F-FoQ\" secondAttribute=\"centerY\" id=\"P1C-mo-lzL\"/>\n                                                            <constraint firstItem=\"bDx-dH-qxB\" firstAttribute=\"centerX\" secondItem=\"eKV-1F-FoQ\" secondAttribute=\"centerX\" id=\"aIh-H5-qhk\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yDe-bK-QPV\">\n                                                        <rect key=\"frame\" x=\"177\" y=\"0.0\" width=\"184\" height=\"183.66666666666666\"/>\n                                                        <subviews>\n                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rPx-x0-3mt\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"-0.3333333333333286\" width=\"184\" height=\"184.33333333333331\"/>\n                                                                <constraints>\n                                                                    <constraint firstAttribute=\"width\" secondItem=\"rPx-x0-3mt\" secondAttribute=\"height\" id=\"o90-Pz-01e\"/>\n                                                                </constraints>\n                                                            </imageView>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"rPx-x0-3mt\" firstAttribute=\"width\" secondItem=\"yDe-bK-QPV\" secondAttribute=\"width\" id=\"Sdt-Vw-U3n\"/>\n                                                            <constraint firstItem=\"rPx-x0-3mt\" firstAttribute=\"centerX\" secondItem=\"yDe-bK-QPV\" secondAttribute=\"centerX\" id=\"TQh-WX-Y2s\"/>\n                                                            <constraint firstItem=\"rPx-x0-3mt\" firstAttribute=\"centerY\" secondItem=\"yDe-bK-QPV\" secondAttribute=\"centerY\" id=\"oSh-Hd-2cc\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"yDe-bK-QPV\" firstAttribute=\"width\" secondItem=\"FVl-Py-pJY\" secondAttribute=\"width\" multiplier=\"0.51\" id=\"GiA-zW-Nld\"/>\n                                                    <constraint firstItem=\"Ibm-Wb-X2B\" firstAttribute=\"width\" secondItem=\"FVl-Py-pJY\" secondAttribute=\"width\" multiplier=\"0.26\" id=\"NfS-HG-Lub\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"FVl-Py-pJY\" firstAttribute=\"top\" secondItem=\"M4e-im-M7y\" secondAttribute=\"top\" id=\"D2Z-8N-lly\"/>\n                                            <constraint firstItem=\"FVl-Py-pJY\" firstAttribute=\"leading\" secondItem=\"M4e-im-M7y\" secondAttribute=\"leading\" id=\"Jfq-HO-rn6\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"FVl-Py-pJY\" secondAttribute=\"trailing\" id=\"pTO-pc-2Fm\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"FVl-Py-pJY\" secondAttribute=\"bottom\" id=\"wyl-R3-oft\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aYT-DM-brI\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"191.66666666666666\" width=\"361\" height=\"46\"/>\n                                        <subviews>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"=\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vhu-G8-3zU\">\n                                                <rect key=\"frame\" x=\"161\" y=\"-15.333333333333314\" width=\"39\" height=\"76.666666666666671\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"64\"/>\n                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"Vhu-G8-3zU\" firstAttribute=\"centerX\" secondItem=\"aYT-DM-brI\" secondAttribute=\"centerX\" id=\"aL7-tr-s1g\"/>\n                                            <constraint firstItem=\"Vhu-G8-3zU\" firstAttribute=\"centerY\" secondItem=\"aYT-DM-brI\" secondAttribute=\"centerY\" id=\"xd2-0C-Vmp\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"71y-uT-PMo\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"245.66666666666671\" width=\"361\" height=\"264.33333333333326\"/>\n                                        <subviews>\n                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zV3-bS-awL\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                <rect key=\"frame\" x=\"48.333333333333343\" y=\"0.0\" width=\"264.33333333333326\" height=\"264.33333333333331\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" secondItem=\"zV3-bS-awL\" secondAttribute=\"height\" id=\"ut3-9s-uPV\"/>\n                                                </constraints>\n                                            </imageView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"zV3-bS-awL\" firstAttribute=\"height\" secondItem=\"71y-uT-PMo\" secondAttribute=\"height\" id=\"Fok-7b-57s\"/>\n                                            <constraint firstItem=\"zV3-bS-awL\" firstAttribute=\"centerX\" secondItem=\"71y-uT-PMo\" secondAttribute=\"centerX\" id=\"N7L-yQ-DT4\"/>\n                                            <constraint firstItem=\"zV3-bS-awL\" firstAttribute=\"centerY\" secondItem=\"71y-uT-PMo\" secondAttribute=\"centerY\" id=\"tRN-TZ-U2F\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"M4e-im-M7y\" firstAttribute=\"height\" secondItem=\"G6N-zZ-vdR\" secondAttribute=\"height\" multiplier=\"0.36\" id=\"2KI-sg-py4\"/>\n                                    <constraint firstItem=\"aYT-DM-brI\" firstAttribute=\"height\" secondItem=\"G6N-zZ-vdR\" secondAttribute=\"height\" multiplier=\"0.09\" id=\"gbj-iK-Wwg\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"G6N-zZ-vdR\" firstAttribute=\"leading\" secondItem=\"BzT-pS-vbj\" secondAttribute=\"leadingMargin\" id=\"AB2-Wc-t8a\"/>\n                            <constraint firstAttribute=\"trailingMargin\" secondItem=\"G6N-zZ-vdR\" secondAttribute=\"trailing\" id=\"URz-eZ-p7b\"/>\n                            <constraint firstItem=\"G6N-zZ-vdR\" firstAttribute=\"top\" secondItem=\"0Vd-W3-apB\" secondAttribute=\"bottom\" id=\"Wbq-tI-hzU\"/>\n                            <constraint firstItem=\"92N-zT-sqV\" firstAttribute=\"top\" secondItem=\"G6N-zZ-vdR\" secondAttribute=\"bottom\" id=\"w4C-j6-rUs\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"603\"/>\n                    <connections>\n                        <outlet property=\"ivBottom\" destination=\"zV3-bS-awL\" id=\"rt9-7J-Tuz\"/>\n                        <outlet property=\"ivTopLeft\" destination=\"IGL-bJ-eTT\" id=\"Tbv-a8-d14\"/>\n                        <outlet property=\"ivTopRight\" destination=\"rPx-x0-3mt\" id=\"N3U-x4-SLq\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"SFy-RP-3aa\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"200.76335877862596\" y=\"-347.53521126760563\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Transform/Use Cases/IntegrateAI.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--IntegrateAI View Controller-->\n        <scene sceneID=\"39j-lv-H81\">\n            <objects>\n                <viewController storyboardIdentifier=\"IntegrateAIViewController\" id=\"DEy-ox-0Qs\" customClass=\"IntegrateAIViewController\" customModule=\"Cloudinary_Example\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"ovq-co-4Ko\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"sj6-xR-yew\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"mTL-8P-xqS\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"603\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Z1h-bJ-x8h\">\n                                <rect key=\"frame\" x=\"16\" y=\"59\" width=\"353\" height=\"510\"/>\n                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                            </view>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"Z1h-bJ-x8h\" firstAttribute=\"leading\" secondItem=\"mTL-8P-xqS\" secondAttribute=\"leadingMargin\" id=\"6ZP-RM-dll\"/>\n                            <constraint firstItem=\"Z1h-bJ-x8h\" firstAttribute=\"top\" secondItem=\"ovq-co-4Ko\" secondAttribute=\"bottom\" id=\"Hfn-I1-NZB\"/>\n                            <constraint firstItem=\"sj6-xR-yew\" firstAttribute=\"top\" secondItem=\"Z1h-bJ-x8h\" secondAttribute=\"bottom\" id=\"fXR-GA-S4x\"/>\n                            <constraint firstAttribute=\"trailingMargin\" secondItem=\"Z1h-bJ-x8h\" secondAttribute=\"trailing\" constant=\"8\" id=\"mwE-2A-9OJ\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"603\"/>\n                    <connections>\n                        <outlet property=\"vwVideoView\" destination=\"Z1h-bJ-x8h\" id=\"8aE-5j-MiF\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"4er-MV-jE1\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"200.76335877862596\" y=\"-347.53521126760563\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Transform/Use Cases/NormalizingProductAssets.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Normalizing Product Assets View Controller-->\n        <scene sceneID=\"9Bw-1I-riS\">\n            <objects>\n                <viewController storyboardIdentifier=\"NormalizingProductAssetsViewController\" id=\"RCI-sz-YRM\" customClass=\"NormalizingProductAssetsViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"NqE-qu-RXI\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"BHr-fr-JB6\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"TUA-6T-ttk\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"603\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacing=\"20\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5md-AO-fAf\">\n                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"361\" height=\"603\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sNo-Uc-bMh\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"371\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NRC-JT-Len\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"371\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Cyp-vW-N8k\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"22.333333333333332\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Before\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7kw-di-5pj\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"1\" width=\"52.666666666666664\" height=\"20.333333333333332\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"semibold\" pointSize=\"17\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"7kw-di-5pj\" firstAttribute=\"leading\" secondItem=\"Cyp-vW-N8k\" secondAttribute=\"leading\" id=\"l6c-Cr-dPc\"/>\n                                                            <constraint firstItem=\"7kw-di-5pj\" firstAttribute=\"centerY\" secondItem=\"Cyp-vW-N8k\" secondAttribute=\"centerY\" id=\"ufT-Zf-sU9\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1Ap-5y-FPQ\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"30.333333333333343\" width=\"361\" height=\"314.33333333333326\"/>\n                                                        <subviews>\n                                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"da2-ng-RFE\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"314.33333333333331\"/>\n                                                                <subviews>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yGZ-fH-aBm\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"180.66666666666666\" height=\"314.33333333333331\"/>\n                                                                        <subviews>\n                                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"o8l-8m-FDA\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"180.66666666666666\" height=\"314.33333333333331\"/>\n                                                                            </imageView>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstItem=\"o8l-8m-FDA\" firstAttribute=\"top\" secondItem=\"yGZ-fH-aBm\" secondAttribute=\"top\" id=\"JPW-fD-eRz\"/>\n                                                                            <constraint firstItem=\"o8l-8m-FDA\" firstAttribute=\"leading\" secondItem=\"yGZ-fH-aBm\" secondAttribute=\"leading\" id=\"TE8-xc-1UZ\"/>\n                                                                            <constraint firstAttribute=\"trailing\" secondItem=\"o8l-8m-FDA\" secondAttribute=\"trailing\" id=\"Y4k-46-bP4\"/>\n                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"o8l-8m-FDA\" secondAttribute=\"bottom\" id=\"n6R-Av-JGD\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ymh-CF-b6Q\">\n                                                                        <rect key=\"frame\" x=\"188.66666666666663\" y=\"0.0\" width=\"172.33333333333337\" height=\"314.33333333333331\"/>\n                                                                        <subviews>\n                                                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"76R-2N-AyA\">\n                                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"172.33333333333334\" height=\"314.33333333333331\"/>\n                                                                                <subviews>\n                                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"I6C-Ja-F8V\">\n                                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"172.33333333333334\" height=\"108.33333333333333\"/>\n                                                                                        <subviews>\n                                                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"to9-Jp-YOJ\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"172.33333333333334\" height=\"108.33333333333333\"/>\n                                                                                            </imageView>\n                                                                                        </subviews>\n                                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                                        <constraints>\n                                                                                            <constraint firstItem=\"to9-Jp-YOJ\" firstAttribute=\"top\" secondItem=\"I6C-Ja-F8V\" secondAttribute=\"top\" id=\"35B-Qh-gzM\"/>\n                                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"to9-Jp-YOJ\" secondAttribute=\"bottom\" id=\"67k-ln-Odd\"/>\n                                                                                            <constraint firstItem=\"to9-Jp-YOJ\" firstAttribute=\"leading\" secondItem=\"I6C-Ja-F8V\" secondAttribute=\"leading\" id=\"LTe-zF-Mbd\"/>\n                                                                                            <constraint firstAttribute=\"trailing\" secondItem=\"to9-Jp-YOJ\" secondAttribute=\"trailing\" id=\"l6D-ci-hV9\"/>\n                                                                                        </constraints>\n                                                                                    </view>\n                                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"khF-jg-bPI\">\n                                                                                        <rect key=\"frame\" x=\"0.0\" y=\"116.33333333333331\" width=\"172.33333333333334\" height=\"198\"/>\n                                                                                        <subviews>\n                                                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"weJ-2b-xgk\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"172.33333333333334\" height=\"198\"/>\n                                                                                            </imageView>\n                                                                                        </subviews>\n                                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                                        <constraints>\n                                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"weJ-2b-xgk\" secondAttribute=\"bottom\" id=\"iHR-oB-cer\"/>\n                                                                                            <constraint firstItem=\"weJ-2b-xgk\" firstAttribute=\"top\" secondItem=\"khF-jg-bPI\" secondAttribute=\"top\" id=\"pGx-yf-cSn\"/>\n                                                                                            <constraint firstItem=\"weJ-2b-xgk\" firstAttribute=\"leading\" secondItem=\"khF-jg-bPI\" secondAttribute=\"leading\" id=\"pvh-BG-A4T\"/>\n                                                                                            <constraint firstAttribute=\"trailing\" secondItem=\"weJ-2b-xgk\" secondAttribute=\"trailing\" id=\"rF0-3G-Wrt\"/>\n                                                                                        </constraints>\n                                                                                    </view>\n                                                                                </subviews>\n                                                                                <constraints>\n                                                                                    <constraint firstItem=\"I6C-Ja-F8V\" firstAttribute=\"height\" secondItem=\"76R-2N-AyA\" secondAttribute=\"height\" multiplier=\"0.345\" id=\"m3b-zQ-Rcx\"/>\n                                                                                </constraints>\n                                                                            </stackView>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstItem=\"76R-2N-AyA\" firstAttribute=\"leading\" secondItem=\"Ymh-CF-b6Q\" secondAttribute=\"leading\" id=\"0zp-qQ-hAD\"/>\n                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"76R-2N-AyA\" secondAttribute=\"bottom\" id=\"FM7-KR-ueW\"/>\n                                                                            <constraint firstItem=\"76R-2N-AyA\" firstAttribute=\"top\" secondItem=\"Ymh-CF-b6Q\" secondAttribute=\"top\" id=\"g6T-B4-wjf\"/>\n                                                                            <constraint firstAttribute=\"trailing\" secondItem=\"76R-2N-AyA\" secondAttribute=\"trailing\" id=\"uZH-5f-4tQ\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                </subviews>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"yGZ-fH-aBm\" firstAttribute=\"width\" secondItem=\"da2-ng-RFE\" secondAttribute=\"width\" multiplier=\"0.5\" id=\"AyG-Bq-Qsu\"/>\n                                                                </constraints>\n                                                            </stackView>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"da2-ng-RFE\" secondAttribute=\"trailing\" id=\"I7n-ED-bnW\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"da2-ng-RFE\" secondAttribute=\"bottom\" id=\"OTi-te-Xxh\"/>\n                                                            <constraint firstItem=\"da2-ng-RFE\" firstAttribute=\"leading\" secondItem=\"1Ap-5y-FPQ\" secondAttribute=\"leading\" id=\"aJ5-Mt-DLx\"/>\n                                                            <constraint firstItem=\"da2-ng-RFE\" firstAttribute=\"top\" secondItem=\"1Ap-5y-FPQ\" secondAttribute=\"top\" id=\"wy4-zW-0o3\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"O7t-hd-Z4G\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"352.66666666666669\" width=\"361\" height=\"18.333333333333314\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"f_auto,q_auto,w_125,h_125,c_limit\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"II1-1Q-WZm\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"2.0000000000000009\" width=\"192\" height=\"14.333333333333336\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"12\"/>\n                                                                <color key=\"textColor\" systemColor=\"systemGray3Color\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"II1-1Q-WZm\" firstAttribute=\"leading\" secondItem=\"O7t-hd-Z4G\" secondAttribute=\"leading\" id=\"Vsf-xD-Pmn\"/>\n                                                            <constraint firstItem=\"II1-1Q-WZm\" firstAttribute=\"centerY\" secondItem=\"O7t-hd-Z4G\" secondAttribute=\"centerY\" id=\"dfm-cR-gGk\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"O7t-hd-Z4G\" firstAttribute=\"height\" secondItem=\"NRC-JT-Len\" secondAttribute=\"height\" multiplier=\"0.049\" id=\"F4S-Ov-cT2\"/>\n                                                    <constraint firstItem=\"Cyp-vW-N8k\" firstAttribute=\"height\" secondItem=\"NRC-JT-Len\" secondAttribute=\"height\" multiplier=\"0.06\" id=\"lx6-yB-SnF\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"NRC-JT-Len\" secondAttribute=\"bottom\" id=\"gR7-wW-nkW\"/>\n                                            <constraint firstItem=\"NRC-JT-Len\" firstAttribute=\"leading\" secondItem=\"sNo-Uc-bMh\" secondAttribute=\"leading\" id=\"gcw-2X-rPx\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"NRC-JT-Len\" secondAttribute=\"trailing\" id=\"tEA-4D-lnY\"/>\n                                            <constraint firstItem=\"NRC-JT-Len\" firstAttribute=\"top\" secondItem=\"sNo-Uc-bMh\" secondAttribute=\"top\" id=\"wNG-1S-SNv\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cda-gb-TOr\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"391\" width=\"361\" height=\"212\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Loz-WK-pOm\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"212\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ihV-Mu-uWT\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"33\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"After\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YvZ-GY-pS3\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"6.3333333333333126\" width=\"40.333333333333336\" height=\"20.333333333333329\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"semibold\" pointSize=\"17\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"YvZ-GY-pS3\" firstAttribute=\"leading\" secondItem=\"ihV-Mu-uWT\" secondAttribute=\"leading\" id=\"81H-a9-E9m\"/>\n                                                            <constraint firstItem=\"YvZ-GY-pS3\" firstAttribute=\"centerY\" secondItem=\"ihV-Mu-uWT\" secondAttribute=\"centerY\" id=\"r67-h5-Jde\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"WYg-yn-XCt\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"32.999999999999993\" width=\"361\" height=\"115.33333333333331\"/>\n                                                        <subviews>\n                                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" distribution=\"fillEqually\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Jn4-SX-jLD\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"115.33333333333333\"/>\n                                                                <subviews>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rnr-dQ-gJY\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"115\" height=\"115.33333333333333\"/>\n                                                                        <subviews>\n                                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"g7o-0z-Hup\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"115\" height=\"115.33333333333333\"/>\n                                                                            </imageView>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstItem=\"g7o-0z-Hup\" firstAttribute=\"top\" secondItem=\"rnr-dQ-gJY\" secondAttribute=\"top\" id=\"NPe-Lu-mum\"/>\n                                                                            <constraint firstItem=\"g7o-0z-Hup\" firstAttribute=\"leading\" secondItem=\"rnr-dQ-gJY\" secondAttribute=\"leading\" id=\"aPT-EL-AiU\"/>\n                                                                            <constraint firstAttribute=\"trailing\" secondItem=\"g7o-0z-Hup\" secondAttribute=\"trailing\" id=\"l3q-ud-UMG\"/>\n                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"g7o-0z-Hup\" secondAttribute=\"bottom\" id=\"wnK-lA-OVe\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hq5-Ek-l9U\">\n                                                                        <rect key=\"frame\" x=\"123\" y=\"0.0\" width=\"115\" height=\"115.33333333333333\"/>\n                                                                        <subviews>\n                                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MzS-GS-mo7\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"115\" height=\"115.33333333333333\"/>\n                                                                            </imageView>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstAttribute=\"trailing\" secondItem=\"MzS-GS-mo7\" secondAttribute=\"trailing\" id=\"Mmx-aH-dCm\"/>\n                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"MzS-GS-mo7\" secondAttribute=\"bottom\" id=\"eZD-T1-7aE\"/>\n                                                                            <constraint firstItem=\"MzS-GS-mo7\" firstAttribute=\"leading\" secondItem=\"hq5-Ek-l9U\" secondAttribute=\"leading\" id=\"nqG-bG-jXf\"/>\n                                                                            <constraint firstItem=\"MzS-GS-mo7\" firstAttribute=\"top\" secondItem=\"hq5-Ek-l9U\" secondAttribute=\"top\" id=\"s3p-6v-X3J\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rLn-MQ-FS2\">\n                                                                        <rect key=\"frame\" x=\"246\" y=\"0.0\" width=\"115\" height=\"115.33333333333333\"/>\n                                                                        <subviews>\n                                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Bhy-gd-ZoJ\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"115\" height=\"115.33333333333333\"/>\n                                                                            </imageView>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstItem=\"Bhy-gd-ZoJ\" firstAttribute=\"top\" secondItem=\"rLn-MQ-FS2\" secondAttribute=\"top\" id=\"H0x-ry-FJo\"/>\n                                                                            <constraint firstAttribute=\"trailing\" secondItem=\"Bhy-gd-ZoJ\" secondAttribute=\"trailing\" id=\"Qw3-EH-ke2\"/>\n                                                                            <constraint firstItem=\"Bhy-gd-ZoJ\" firstAttribute=\"leading\" secondItem=\"rLn-MQ-FS2\" secondAttribute=\"leading\" id=\"bRE-H1-tF0\"/>\n                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"Bhy-gd-ZoJ\" secondAttribute=\"bottom\" id=\"rLY-E8-mxs\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                </subviews>\n                                                            </stackView>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"Jn4-SX-jLD\" secondAttribute=\"trailing\" id=\"7X8-9z-pDf\"/>\n                                                            <constraint firstItem=\"Jn4-SX-jLD\" firstAttribute=\"leading\" secondItem=\"WYg-yn-XCt\" secondAttribute=\"leading\" id=\"NAO-hl-Hyh\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"Jn4-SX-jLD\" secondAttribute=\"bottom\" id=\"b5Q-M8-5Dq\"/>\n                                                            <constraint firstItem=\"Jn4-SX-jLD\" firstAttribute=\"top\" secondItem=\"WYg-yn-XCt\" secondAttribute=\"top\" id=\"sad-if-kDk\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lL2-bG-mYz\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"148.33333333333337\" width=\"361\" height=\"63.666666666666657\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"e_trim/ f_auto,q_auto:low,dpr_2.0,c_pad,b_auto,w_125, h_125\" textAlignment=\"natural\" lineBreakMode=\"wordWrap\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nmV-Is-QGt\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"63.666666666666664\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"12\"/>\n                                                                <color key=\"textColor\" systemColor=\"systemGray3Color\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"nmV-Is-QGt\" secondAttribute=\"bottom\" id=\"B6Z-7a-wZD\"/>\n                                                            <constraint firstItem=\"nmV-Is-QGt\" firstAttribute=\"centerY\" secondItem=\"lL2-bG-mYz\" secondAttribute=\"centerY\" id=\"Er0-Ln-IlD\"/>\n                                                            <constraint firstItem=\"nmV-Is-QGt\" firstAttribute=\"top\" secondItem=\"lL2-bG-mYz\" secondAttribute=\"top\" id=\"Qwy-Et-iho\"/>\n                                                            <constraint firstItem=\"nmV-Is-QGt\" firstAttribute=\"leading\" secondItem=\"lL2-bG-mYz\" secondAttribute=\"leading\" id=\"Uz4-x2-JTp\"/>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"nmV-Is-QGt\" secondAttribute=\"trailing\" id=\"Y04-Vb-93e\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"ihV-Mu-uWT\" firstAttribute=\"height\" secondItem=\"Loz-WK-pOm\" secondAttribute=\"height\" multiplier=\"0.156\" id=\"7ZS-fR-pgX\"/>\n                                                    <constraint firstItem=\"lL2-bG-mYz\" firstAttribute=\"height\" secondItem=\"Loz-WK-pOm\" secondAttribute=\"height\" multiplier=\"0.3\" id=\"VdY-Nz-i7d\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"Loz-WK-pOm\" firstAttribute=\"leading\" secondItem=\"cda-gb-TOr\" secondAttribute=\"leading\" id=\"1cW-Wm-YPX\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"Loz-WK-pOm\" secondAttribute=\"bottom\" id=\"gRA-iY-Gxz\"/>\n                                            <constraint firstItem=\"Loz-WK-pOm\" firstAttribute=\"top\" secondItem=\"cda-gb-TOr\" secondAttribute=\"top\" id=\"vE6-vC-bJB\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"Loz-WK-pOm\" secondAttribute=\"trailing\" id=\"xll-Go-TKe\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"sNo-Uc-bMh\" firstAttribute=\"height\" secondItem=\"5md-AO-fAf\" secondAttribute=\"height\" multiplier=\"0.615\" id=\"6Ka-8t-mnN\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"5md-AO-fAf\" firstAttribute=\"top\" secondItem=\"TUA-6T-ttk\" secondAttribute=\"top\" id=\"Di1-V3-LBj\"/>\n                            <constraint firstItem=\"5md-AO-fAf\" firstAttribute=\"leading\" secondItem=\"TUA-6T-ttk\" secondAttribute=\"leading\" constant=\"16\" id=\"Mxg-VC-6YC\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"5md-AO-fAf\" secondAttribute=\"bottom\" id=\"nhJ-qf-ogH\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"5md-AO-fAf\" secondAttribute=\"trailing\" constant=\"16\" id=\"yR2-gp-jED\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"603\"/>\n                    <connections>\n                        <outlet property=\"ivBottomLeft\" destination=\"g7o-0z-Hup\" id=\"ZfG-TK-NFp\"/>\n                        <outlet property=\"ivBottomMid\" destination=\"MzS-GS-mo7\" id=\"xIK-kB-nGw\"/>\n                        <outlet property=\"ivBottomRight\" destination=\"Bhy-gd-ZoJ\" id=\"fhq-BK-sZ6\"/>\n                        <outlet property=\"ivMidRight\" destination=\"weJ-2b-xgk\" id=\"vLv-h5-Flc\"/>\n                        <outlet property=\"ivTopLeft\" destination=\"o8l-8m-FDA\" id=\"DHm-s0-QCq\"/>\n                        <outlet property=\"ivTopRight\" destination=\"to9-Jp-YOJ\" id=\"Z27-Yn-Gdh\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"4N7-eZ-IYV\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-25.190839694656489\" y=\"3.8732394366197185\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <systemColor name=\"systemGray3Color\">\n            <color red=\"0.78039215689999997\" green=\"0.78039215689999997\" blue=\"0.80000000000000004\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Transform/UseCases.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"collection view cell content view\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Use Cases View Controller-->\n        <scene sceneID=\"VCM-3g-PdS\">\n            <objects>\n                <viewController storyboardIdentifier=\"UseCasesViewController\" id=\"aoO-4V-GGJ\" customClass=\"UseCasesViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"Fas-vQ-G2X\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"MBc-I6-YAN\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5Jb-Cm-qr2\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacing=\"10\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9Mw-Hx-Alz\">\n                                <rect key=\"frame\" x=\"16\" y=\"59\" width=\"361\" height=\"761\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lW3-c5-eku\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"593.66666666666663\"/>\n                                        <subviews>\n                                            <containerView opaque=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Zup-qN-DLo\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"593.66666666666663\"/>\n                                            </containerView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"Zup-qN-DLo\" firstAttribute=\"top\" secondItem=\"lW3-c5-eku\" secondAttribute=\"top\" id=\"I3b-6R-uPG\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"Zup-qN-DLo\" secondAttribute=\"trailing\" id=\"VZN-gX-xCR\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"Zup-qN-DLo\" secondAttribute=\"bottom\" id=\"Wym-Ge-RLV\"/>\n                                            <constraint firstItem=\"Zup-qN-DLo\" firstAttribute=\"leading\" secondItem=\"lW3-c5-eku\" secondAttribute=\"leading\" id=\"jDT-lD-5pb\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bK6-R7-IBS\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"603.66666666666663\" width=\"361\" height=\"157.33333333333337\"/>\n                                        <subviews>\n                                            <collectionView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" dataMode=\"prototypes\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"joS-mn-pfX\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"157.33333333333334\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <collectionViewFlowLayout key=\"collectionViewLayout\" scrollDirection=\"horizontal\" minimumLineSpacing=\"0.0\" minimumInteritemSpacing=\"12\" id=\"kz8-Nh-tuN\">\n                                                    <size key=\"itemSize\" width=\"80\" height=\"116\"/>\n                                                    <size key=\"headerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <size key=\"footerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <inset key=\"sectionInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                                </collectionViewFlowLayout>\n                                                <cells>\n                                                    <collectionViewCell opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" reuseIdentifier=\"UseCaseCollectionCell\" id=\"Jey-sY-icW\" customClass=\"UseCaseCollectionCell\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"20.666666666666668\" width=\"80\" height=\"116\"/>\n                                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                        <collectionViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"CpN-Cm-OHf\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"80\" height=\"116\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                            <subviews>\n                                                                <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"n1l-Ot-fR3\" customClass=\"GradientView\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"80\" height=\"116\"/>\n                                                                    <subviews>\n                                                                        <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Normalizing Product Assets - Sizing\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"4\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jTM-vJ-rQa\">\n                                                                            <rect key=\"frame\" x=\"4\" y=\"29.333333333333332\" width=\"72\" height=\"57.333333333333343\"/>\n                                                                            <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"12\"/>\n                                                                            <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                            <nil key=\"highlightedColor\"/>\n                                                                            <lineBreakStrategy key=\"lineBreakStrategy\" pushOut=\"YES\"/>\n                                                                        </label>\n                                                                    </subviews>\n                                                                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                    <constraints>\n                                                                        <constraint firstItem=\"jTM-vJ-rQa\" firstAttribute=\"centerX\" secondItem=\"n1l-Ot-fR3\" secondAttribute=\"centerX\" id=\"TFE-aU-RUR\"/>\n                                                                        <constraint firstItem=\"jTM-vJ-rQa\" firstAttribute=\"leading\" secondItem=\"n1l-Ot-fR3\" secondAttribute=\"leading\" constant=\"4\" id=\"hj5-KY-a3f\"/>\n                                                                        <constraint firstItem=\"jTM-vJ-rQa\" firstAttribute=\"centerY\" secondItem=\"n1l-Ot-fR3\" secondAttribute=\"centerY\" id=\"keO-Xn-jDc\"/>\n                                                                    </constraints>\n                                                                    <userDefinedRuntimeAttributes>\n                                                                        <userDefinedRuntimeAttribute type=\"color\" keyPath=\"firstColor\">\n                                                                            <color key=\"value\" name=\"gradient-first\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"color\" keyPath=\"secondColor\">\n                                                                            <color key=\"value\" name=\"gradient-second\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                            <integer key=\"value\" value=\"4\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                    </userDefinedRuntimeAttributes>\n                                                                </view>\n                                                            </subviews>\n                                                            <constraints>\n                                                                <constraint firstItem=\"n1l-Ot-fR3\" firstAttribute=\"leading\" secondItem=\"CpN-Cm-OHf\" secondAttribute=\"leading\" id=\"4vE-Sz-pgJ\"/>\n                                                                <constraint firstItem=\"n1l-Ot-fR3\" firstAttribute=\"top\" secondItem=\"CpN-Cm-OHf\" secondAttribute=\"top\" id=\"ILU-i0-ZSx\"/>\n                                                                <constraint firstAttribute=\"trailing\" secondItem=\"n1l-Ot-fR3\" secondAttribute=\"trailing\" id=\"OJu-or-4nt\"/>\n                                                                <constraint firstAttribute=\"bottom\" secondItem=\"n1l-Ot-fR3\" secondAttribute=\"bottom\" id=\"WYv-li-2DW\"/>\n                                                            </constraints>\n                                                            <userDefinedRuntimeAttributes>\n                                                                <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                    <integer key=\"value\" value=\"4\"/>\n                                                                </userDefinedRuntimeAttribute>\n                                                                <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                            </userDefinedRuntimeAttributes>\n                                                        </collectionViewCellContentView>\n                                                        <size key=\"customSize\" width=\"80\" height=\"116\"/>\n                                                        <connections>\n                                                            <outlet property=\"lbMain\" destination=\"jTM-vJ-rQa\" id=\"rbV-le-bPx\"/>\n                                                        </connections>\n                                                    </collectionViewCell>\n                                                </cells>\n                                            </collectionView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"joS-mn-pfX\" firstAttribute=\"leading\" secondItem=\"bK6-R7-IBS\" secondAttribute=\"leading\" id=\"54i-O3-a8m\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"joS-mn-pfX\" secondAttribute=\"trailing\" id=\"5cz-Fq-6xw\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"joS-mn-pfX\" secondAttribute=\"bottom\" id=\"93G-1F-kKW\"/>\n                                            <constraint firstItem=\"joS-mn-pfX\" firstAttribute=\"top\" secondItem=\"bK6-R7-IBS\" secondAttribute=\"top\" id=\"SOe-Uo-Ne1\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"lW3-c5-eku\" firstAttribute=\"height\" secondItem=\"9Mw-Hx-Alz\" secondAttribute=\"height\" multiplier=\"0.78\" id=\"ueE-xx-Uxr\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"9Mw-Hx-Alz\" secondAttribute=\"trailing\" constant=\"16\" id=\"8OZ-jF-vWB\"/>\n                            <constraint firstItem=\"9Mw-Hx-Alz\" firstAttribute=\"leading\" secondItem=\"5Jb-Cm-qr2\" secondAttribute=\"leading\" constant=\"16\" id=\"JV6-kf-uHA\"/>\n                            <constraint firstItem=\"9Mw-Hx-Alz\" firstAttribute=\"top\" secondItem=\"Fas-vQ-G2X\" secondAttribute=\"bottom\" id=\"VjG-g1-9b2\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"9Mw-Hx-Alz\" secondAttribute=\"bottom\" constant=\"32\" id=\"ryR-WK-G1q\"/>\n                        </constraints>\n                    </view>\n                    <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n                    <connections>\n                        <outlet property=\"cvMain\" destination=\"joS-mn-pfX\" id=\"2bi-bX-qj4\"/>\n                        <outlet property=\"vwContainer\" destination=\"Zup-qN-DLo\" id=\"7mm-Zk-Ewa\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"6ef-GB-hOT\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"129.00763358778624\" y=\"-2.1126760563380285\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <namedColor name=\"gradient-first\">\n            <color red=\"0.20392156859999999\" green=\"0.28235294119999998\" blue=\"0.7725490196\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"gradient-second\">\n            <color red=\"0.15686274510000001\" green=\"0.73333333329999995\" blue=\"0.98039215690000003\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Upload/InnerUploadFrame.xib",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <objects>\n        <placeholder placeholderIdentifier=\"IBFilesOwner\" id=\"-1\" userLabel=\"File's Owner\" customClass=\"InnerUploadFrame\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n            <connections>\n                <outlet property=\"lbSubtitle\" destination=\"dGm-wg-VI2\" id=\"bGb-75-j1k\"/>\n                <outlet property=\"lbTitle\" destination=\"Oe5-7C-DCz\" id=\"9jO-wW-zz7\"/>\n                <outlet property=\"vwGradientView\" destination=\"ttu-VH-c8j\" id=\"m67-ro-aq3\"/>\n            </connections>\n        </placeholder>\n        <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"-2\" customClass=\"UIResponder\"/>\n        <view contentMode=\"scaleToFill\" id=\"iN0-l3-epB\">\n            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"187\"/>\n            <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n            <subviews>\n                <view clipsSubviews=\"YES\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aVS-xr-u8h\">\n                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"187\"/>\n                    <subviews>\n                        <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ulz-zA-MyS\">\n                            <rect key=\"frame\" x=\"30\" y=\"50\" width=\"200\" height=\"87\"/>\n                            <subviews>\n                                <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"B3d-AO-9tU\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"200\" height=\"22.666666666666668\"/>\n                                    <subviews>\n                                        <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Upload\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Oe5-7C-DCz\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.3333333333333357\" width=\"59\" height=\"21.666666666666668\"/>\n                                            <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                            <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                            <nil key=\"highlightedColor\"/>\n                                        </label>\n                                    </subviews>\n                                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                    <constraints>\n                                        <constraint firstItem=\"Oe5-7C-DCz\" firstAttribute=\"leading\" secondItem=\"B3d-AO-9tU\" secondAttribute=\"leading\" id=\"JKt-8c-EeT\"/>\n                                        <constraint firstItem=\"Oe5-7C-DCz\" firstAttribute=\"centerY\" secondItem=\"B3d-AO-9tU\" secondAttribute=\"centerY\" id=\"QjN-6J-yqb\"/>\n                                    </constraints>\n                                </view>\n                                <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aew-vh-zgD\">\n                                    <rect key=\"frame\" x=\"0.0\" y=\"30.666666666666675\" width=\"200\" height=\"56.333333333333343\"/>\n                                    <subviews>\n                                        <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Everything starts when you uploads a file\" textAlignment=\"natural\" lineBreakMode=\"wordWrap\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dGm-wg-VI2\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"200\" height=\"56.333333333333336\"/>\n                                            <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                            <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                            <nil key=\"highlightedColor\"/>\n                                        </label>\n                                    </subviews>\n                                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                    <constraints>\n                                        <constraint firstItem=\"dGm-wg-VI2\" firstAttribute=\"leading\" secondItem=\"aew-vh-zgD\" secondAttribute=\"leading\" id=\"00I-8V-0AT\"/>\n                                        <constraint firstItem=\"dGm-wg-VI2\" firstAttribute=\"leading\" secondItem=\"aew-vh-zgD\" secondAttribute=\"leading\" id=\"1jR-oF-UEJ\"/>\n                                        <constraint firstItem=\"dGm-wg-VI2\" firstAttribute=\"top\" secondItem=\"aew-vh-zgD\" secondAttribute=\"top\" id=\"5ci-Hu-JYg\"/>\n                                        <constraint firstAttribute=\"trailing\" secondItem=\"dGm-wg-VI2\" secondAttribute=\"trailing\" id=\"UTG-sV-rrm\"/>\n                                        <constraint firstAttribute=\"bottom\" secondItem=\"dGm-wg-VI2\" secondAttribute=\"bottom\" id=\"koX-2N-9wi\"/>\n                                    </constraints>\n                                </view>\n                            </subviews>\n                            <constraints>\n                                <constraint firstItem=\"B3d-AO-9tU\" firstAttribute=\"height\" secondItem=\"ulz-zA-MyS\" secondAttribute=\"height\" multiplier=\"0.26\" id=\"y6B-6z-Kpw\"/>\n                            </constraints>\n                        </stackView>\n                        <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ttu-VH-c8j\" customClass=\"GradientView\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                            <rect key=\"frame\" x=\"264\" y=\"-34\" width=\"227\" height=\"255\"/>\n                            <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                            <constraints>\n                                <constraint firstAttribute=\"width\" secondItem=\"ttu-VH-c8j\" secondAttribute=\"height\" multiplier=\"227:255\" id=\"eoA-j5-QhQ\"/>\n                            </constraints>\n                        </view>\n                    </subviews>\n                    <color key=\"backgroundColor\" name=\"secondary\"/>\n                    <constraints>\n                        <constraint firstItem=\"ulz-zA-MyS\" firstAttribute=\"top\" secondItem=\"aVS-xr-u8h\" secondAttribute=\"top\" constant=\"50\" id=\"9EW-ef-PWi\"/>\n                        <constraint firstAttribute=\"bottom\" secondItem=\"ulz-zA-MyS\" secondAttribute=\"bottom\" constant=\"50\" id=\"aOm-id-Jgp\"/>\n                        <constraint firstAttribute=\"trailing\" secondItem=\"ttu-VH-c8j\" secondAttribute=\"trailing\" constant=\"-130\" id=\"bbG-Tt-sl6\"/>\n                        <constraint firstItem=\"ttu-VH-c8j\" firstAttribute=\"centerY\" secondItem=\"aVS-xr-u8h\" secondAttribute=\"centerY\" id=\"h1J-sE-MxR\"/>\n                        <constraint firstItem=\"ulz-zA-MyS\" firstAttribute=\"width\" secondItem=\"aVS-xr-u8h\" secondAttribute=\"width\" multiplier=\"0.554017\" id=\"sRW-P5-ssD\"/>\n                        <constraint firstItem=\"ulz-zA-MyS\" firstAttribute=\"leading\" secondItem=\"aVS-xr-u8h\" secondAttribute=\"leading\" constant=\"30\" id=\"tfS-m8-RcY\"/>\n                        <constraint firstItem=\"ttu-VH-c8j\" firstAttribute=\"width\" secondItem=\"aVS-xr-u8h\" secondAttribute=\"width\" multiplier=\"0.628809\" id=\"xMs-Th-GZp\"/>\n                    </constraints>\n                </view>\n            </subviews>\n            <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n            <constraints>\n                <constraint firstItem=\"aVS-xr-u8h\" firstAttribute=\"leading\" secondItem=\"iN0-l3-epB\" secondAttribute=\"leading\" id=\"Jtd-ed-gfg\"/>\n                <constraint firstAttribute=\"bottom\" secondItem=\"aVS-xr-u8h\" secondAttribute=\"bottom\" id=\"LUc-ep-78x\"/>\n                <constraint firstAttribute=\"trailing\" secondItem=\"aVS-xr-u8h\" secondAttribute=\"trailing\" id=\"U8B-Ay-GOa\"/>\n                <constraint firstItem=\"aVS-xr-u8h\" firstAttribute=\"top\" secondItem=\"iN0-l3-epB\" secondAttribute=\"top\" id=\"l7N-1P-goD\"/>\n            </constraints>\n            <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n            <point key=\"canvasLocation\" x=\"74\" y=\"20\"/>\n        </view>\n    </objects>\n    <resources>\n        <namedColor name=\"secondary\">\n            <color red=\"0.24705882352941178\" green=\"0.27843137254901962\" blue=\"0.35294117647058826\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Upload/Upload.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Upload View Controller-->\n        <scene sceneID=\"s0d-6b-0kx\">\n            <objects>\n                <viewController storyboardIdentifier=\"UploadViewController\" id=\"Y6W-OH-hqX\" customClass=\"UploadViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5EZ-qb-Rvc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vtr-bN-ruS\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"59\" width=\"393\" height=\"759\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ydZ-NJ-7ec\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"102.33333333333333\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AXB-Z6-bUn\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"102.33333333333333\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8za-2X-cID\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"66.666666666666671\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Upload\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zFB-po-Deh\">\n                                                                <rect key=\"frame\" x=\"16.000000000000007\" y=\"11.666666666666671\" width=\"116.66666666666669\" height=\"43\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"semibold\" pointSize=\"36\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"zFB-po-Deh\" secondAttribute=\"bottom\" constant=\"12\" id=\"aR1-Lw-8aR\"/>\n                                                            <constraint firstItem=\"zFB-po-Deh\" firstAttribute=\"leading\" secondItem=\"8za-2X-cID\" secondAttribute=\"leading\" constant=\"16\" id=\"iaD-FD-0uW\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ooe-Ji-DpA\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"66.666666666666671\" width=\"393\" height=\"35.666666666666671\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Dht-dh-MMo\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"47\" height=\"5\"/>\n                                                                <color key=\"backgroundColor\" name=\"primary\"/>\n                                                                <constraints>\n                                                                    <constraint firstAttribute=\"height\" constant=\"5\" id=\"f2W-ga-DAZ\"/>\n                                                                </constraints>\n                                                                <userDefinedRuntimeAttributes>\n                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                        <real key=\"value\" value=\"2.5\"/>\n                                                                    </userDefinedRuntimeAttribute>\n                                                                </userDefinedRuntimeAttributes>\n                                                            </view>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"Dht-dh-MMo\" firstAttribute=\"top\" secondItem=\"ooe-Ji-DpA\" secondAttribute=\"top\" id=\"95g-cK-jIk\"/>\n                                                            <constraint firstItem=\"Dht-dh-MMo\" firstAttribute=\"width\" secondItem=\"ooe-Ji-DpA\" secondAttribute=\"width\" multiplier=\"0.119593\" id=\"He9-oo-MJF\"/>\n                                                            <constraint firstItem=\"Dht-dh-MMo\" firstAttribute=\"leading\" secondItem=\"ooe-Ji-DpA\" secondAttribute=\"leading\" constant=\"16\" id=\"lag-OT-ixb\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"8za-2X-cID\" firstAttribute=\"height\" secondItem=\"AXB-Z6-bUn\" secondAttribute=\"height\" multiplier=\"0.65\" id=\"obG-FG-9xY\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"AXB-Z6-bUn\" secondAttribute=\"trailing\" id=\"6ZE-gk-92p\"/>\n                                            <constraint firstItem=\"AXB-Z6-bUn\" firstAttribute=\"leading\" secondItem=\"ydZ-NJ-7ec\" secondAttribute=\"leading\" id=\"LDR-Z9-Wb9\"/>\n                                            <constraint firstItem=\"AXB-Z6-bUn\" firstAttribute=\"top\" secondItem=\"ydZ-NJ-7ec\" secondAttribute=\"top\" id=\"Li4-gR-Rxb\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"AXB-Z6-bUn\" secondAttribute=\"bottom\" id=\"kUS-20-QEH\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JcN-j9-is5\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"102.33333333333334\" width=\"393\" height=\"47.333333333333343\"/>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ob4-mv-2CE\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"149.66666666666669\" width=\"393\" height=\"603.33333333333326\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" distribution=\"fillEqually\" spacing=\"20\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vtM-Kl-hCs\">\n                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"361\" height=\"603.33333333333337\"/>\n                                                <subviews>\n                                                    <view clipsSubviews=\"YES\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fDr-OC-wuL\" customClass=\"InnerUploadFrame\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"187.66666666666666\"/>\n                                                        <color key=\"backgroundColor\" name=\"secondary\"/>\n                                                    </view>\n                                                    <view clipsSubviews=\"YES\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9nB-Zz-BF4\" customClass=\"InnerUploadFrame\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"207.66666666666669\" width=\"361\" height=\"187.66666666666669\"/>\n                                                        <color key=\"backgroundColor\" name=\"secondary\"/>\n                                                    </view>\n                                                    <view clipsSubviews=\"YES\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fQF-0a-hO0\" customClass=\"InnerUploadFrame\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"415.33333333333337\" width=\"361\" height=\"188\"/>\n                                                        <color key=\"backgroundColor\" name=\"secondary\"/>\n                                                    </view>\n                                                </subviews>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"vtM-Kl-hCs\" secondAttribute=\"bottom\" id=\"PQ1-If-FUd\"/>\n                                            <constraint firstItem=\"vtM-Kl-hCs\" firstAttribute=\"top\" secondItem=\"ob4-mv-2CE\" secondAttribute=\"top\" id=\"SIC-b1-lyo\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"vtM-Kl-hCs\" secondAttribute=\"trailing\" constant=\"16\" id=\"VWF-d4-sOf\"/>\n                                            <constraint firstItem=\"vtM-Kl-hCs\" firstAttribute=\"leading\" secondItem=\"ob4-mv-2CE\" secondAttribute=\"leading\" constant=\"16\" id=\"xDR-fH-bTg\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bih-dk-Mmq\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"753\" width=\"393\" height=\"6\"/>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"JcN-j9-is5\" firstAttribute=\"height\" secondItem=\"Vtr-bN-ruS\" secondAttribute=\"height\" multiplier=\"0.062\" id=\"0Cx-YB-Cyg\"/>\n                                    <constraint firstItem=\"ydZ-NJ-7ec\" firstAttribute=\"height\" secondItem=\"Vtr-bN-ruS\" secondAttribute=\"height\" multiplier=\"0.135\" id=\"3oX-0j-FPB\"/>\n                                    <constraint firstItem=\"ob4-mv-2CE\" firstAttribute=\"height\" secondItem=\"Vtr-bN-ruS\" secondAttribute=\"height\" multiplier=\"0.795\" id=\"XU1-vR-Sn9\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"vDu-zF-Fre\"/>\n                        <color key=\"backgroundColor\" name=\"surface\"/>\n                        <constraints>\n                            <constraint firstItem=\"vDu-zF-Fre\" firstAttribute=\"trailing\" secondItem=\"Vtr-bN-ruS\" secondAttribute=\"trailing\" id=\"Zq5-tV-68I\"/>\n                            <constraint firstItem=\"Vtr-bN-ruS\" firstAttribute=\"leading\" secondItem=\"vDu-zF-Fre\" secondAttribute=\"leading\" id=\"enx-I3-zEa\"/>\n                            <constraint firstItem=\"Vtr-bN-ruS\" firstAttribute=\"bottom\" secondItem=\"vDu-zF-Fre\" secondAttribute=\"bottom\" id=\"hDf-l3-Tk7\"/>\n                            <constraint firstItem=\"vDu-zF-Fre\" firstAttribute=\"top\" secondItem=\"Vtr-bN-ruS\" secondAttribute=\"top\" id=\"oPx-ab-cLU\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"lbTitle\" destination=\"zFB-po-Deh\" id=\"bpd-fV-SO3\"/>\n                        <outlet property=\"vwFetchUpload\" destination=\"fQF-0a-hO0\" id=\"XXG-qr-ffl\"/>\n                        <outlet property=\"vwUpload\" destination=\"fDr-OC-wuL\" id=\"c7w-Fz-e9u\"/>\n                        <outlet property=\"vwUploadLarge\" destination=\"9nB-Zz-BF4\" id=\"kaW-MH-ReX\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Ief-a0-LHa\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"139\" y=\"-2\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <namedColor name=\"primary\">\n            <color red=\"0.27450980392156865\" green=\"0.59607843137254901\" blue=\"0.96862745098039216\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"secondary\">\n            <color red=\"0.24705882352941178\" green=\"0.27843137254901962\" blue=\"0.35294117647058826\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"surface\">\n            <color red=\"0.12549019607843137\" green=\"0.14117647058823529\" blue=\"0.17647058823529413\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Upload/UploadNoCloud.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Upload No Cloud Controller-->\n        <scene sceneID=\"s0d-6b-0kx\">\n            <objects>\n                <viewController storyboardIdentifier=\"UploadNoCloudController\" id=\"Y6W-OH-hqX\" customClass=\"UploadNoCloudController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"rht-LB-R9i\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"QOw-8g-xS4\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5EZ-qb-Rvc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"center\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"splash_without_logo\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wgW-d3-5fz\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                            </imageView>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QUw-Ge-iDz\">\n                                <rect key=\"frame\" x=\"30\" y=\"266.66666666666669\" width=\"333\" height=\"319.00000000000006\"/>\n                                <subviews>\n                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ff8-UG-dZY\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"333\" height=\"319\"/>\n                                        <subviews>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3wo-Mt-fmw\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"333\" height=\"82.666666666666671\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Hi,  Developers!\" textAlignment=\"natural\" lineBreakMode=\"wordWrap\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Z3g-E4-dfO\" userLabel=\"Hi,  Developers!\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"333\" height=\"86\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"semibold\" pointSize=\"36\"/>\n                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"Z3g-E4-dfO\" firstAttribute=\"top\" secondItem=\"3wo-Mt-fmw\" secondAttribute=\"top\" id=\"1WO-hd-Fxs\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"Z3g-E4-dfO\" secondAttribute=\"trailing\" id=\"bpf-ar-r1z\"/>\n                                                    <constraint firstItem=\"Z3g-E4-dfO\" firstAttribute=\"leading\" secondItem=\"3wo-Mt-fmw\" secondAttribute=\"leading\" id=\"tIJ-YB-I8C\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"1dY-ve-QjQ\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"82.666666666666629\" width=\"333\" height=\"83\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Insert your cloud name and explore  Cloudinary's power effortlessly.\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ac9-B6-tVn\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"333\" height=\"83\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"Ac9-B6-tVn\" secondAttribute=\"trailing\" id=\"4xK-ui-NKh\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"Ac9-B6-tVn\" secondAttribute=\"bottom\" id=\"8JZ-ml-7uE\"/>\n                                                    <constraint firstItem=\"Ac9-B6-tVn\" firstAttribute=\"leading\" secondItem=\"1dY-ve-QjQ\" secondAttribute=\"leading\" id=\"MI5-6J-WG0\"/>\n                                                    <constraint firstItem=\"Ac9-B6-tVn\" firstAttribute=\"top\" secondItem=\"1dY-ve-QjQ\" secondAttribute=\"top\" id=\"zQo-3p-wdf\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Gfs-SL-cU8\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"165.66666666666663\" width=\"333\" height=\"60.666666666666657\"/>\n                                                <subviews>\n                                                    <textField opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"248\" contentHorizontalAlignment=\"left\" contentVerticalAlignment=\"center\" borderStyle=\"line\" placeholder=\"Cloud Name\" textAlignment=\"natural\" minimumFontSize=\"18\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Dyc-Pr-WD2\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"333\" height=\"40\"/>\n                                                        <color key=\"backgroundColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" secondItem=\"Dyc-Pr-WD2\" secondAttribute=\"height\" multiplier=\"333:40\" id=\"Row-M9-ln7\"/>\n                                                        </constraints>\n                                                        <color key=\"textColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"16\"/>\n                                                        <textInputTraits key=\"textInputTraits\"/>\n                                                    </textField>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"Dyc-Pr-WD2\" secondAttribute=\"trailing\" id=\"KNl-d7-LFn\"/>\n                                                    <constraint firstItem=\"Dyc-Pr-WD2\" firstAttribute=\"top\" secondItem=\"Gfs-SL-cU8\" secondAttribute=\"top\" id=\"RQY-Ub-kYh\"/>\n                                                    <constraint firstItem=\"Dyc-Pr-WD2\" firstAttribute=\"leading\" secondItem=\"Gfs-SL-cU8\" secondAttribute=\"leading\" id=\"oo3-su-Y6L\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"h7N-Pp-L64\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"226.33333333333331\" width=\"333\" height=\"57.333333333333314\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iJR-Ls-NyD\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"1.3333333333333144\" width=\"333\" height=\"55\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Get Started\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8ne-Zc-XzH\">\n                                                                <rect key=\"frame\" x=\"118\" y=\"16.666666666666686\" width=\"97\" height=\"21.666666666666671\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"semibold\" pointSize=\"18\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" name=\"gradient-first\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" secondItem=\"iJR-Ls-NyD\" secondAttribute=\"height\" multiplier=\"333:55\" id=\"VdU-hN-tLK\"/>\n                                                            <constraint firstItem=\"8ne-Zc-XzH\" firstAttribute=\"centerX\" secondItem=\"iJR-Ls-NyD\" secondAttribute=\"centerX\" id=\"j8r-Bf-Tl4\"/>\n                                                            <constraint firstItem=\"8ne-Zc-XzH\" firstAttribute=\"centerY\" secondItem=\"iJR-Ls-NyD\" secondAttribute=\"centerY\" id=\"nlt-Sm-itp\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"iJR-Ls-NyD\" firstAttribute=\"width\" secondItem=\"h7N-Pp-L64\" secondAttribute=\"width\" id=\"4bj-xc-Z0a\"/>\n                                                    <constraint firstItem=\"iJR-Ls-NyD\" firstAttribute=\"centerY\" secondItem=\"h7N-Pp-L64\" secondAttribute=\"centerY\" id=\"YIN-C6-Lha\"/>\n                                                    <constraint firstItem=\"iJR-Ls-NyD\" firstAttribute=\"centerX\" secondItem=\"h7N-Pp-L64\" secondAttribute=\"centerX\" id=\"ffX-iT-sea\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oBy-GA-5e4\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"283.66666666666669\" width=\"333\" height=\"35.333333333333314\"/>\n                                                <subviews>\n                                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xMO-F4-tcZ\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"333\" height=\"35.333333333333336\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yJd-Jb-qnY\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"179.66666666666666\" height=\"35.333333333333336\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Can’t find the cloud name?\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8bg-sS-GsW\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"18.333333333333258\" width=\"179.66666666666666\" height=\"17\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstAttribute=\"trailing\" secondItem=\"8bg-sS-GsW\" secondAttribute=\"trailing\" id=\"Hmw-39-idW\"/>\n                                                                    <constraint firstItem=\"8bg-sS-GsW\" firstAttribute=\"leading\" secondItem=\"yJd-Jb-qnY\" secondAttribute=\"leading\" id=\"cUJ-6h-sUB\"/>\n                                                                    <constraint firstAttribute=\"bottom\" secondItem=\"8bg-sS-GsW\" secondAttribute=\"bottom\" id=\"qvG-wY-7zz\"/>\n                                                                </constraints>\n                                                            </view>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Pc4-ai-AKq\">\n                                                                <rect key=\"frame\" x=\"179.66666666666663\" y=\"0.0\" width=\"153.33333333333337\" height=\"35.333333333333336\"/>\n                                                                <subviews>\n                                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"question_mark\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Oc1-jQ-wrY\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"17\" width=\"18.333333333333332\" height=\"18.333333333333329\"/>\n                                                                        <constraints>\n                                                                            <constraint firstAttribute=\"width\" secondItem=\"Oc1-jQ-wrY\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"CEr-ll-vEc\"/>\n                                                                        </constraints>\n                                                                    </imageView>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"Oc1-jQ-wrY\" firstAttribute=\"leading\" secondItem=\"Pc4-ai-AKq\" secondAttribute=\"leading\" id=\"KfF-FW-afB\"/>\n                                                                    <constraint firstAttribute=\"bottom\" secondItem=\"Oc1-jQ-wrY\" secondAttribute=\"bottom\" id=\"TKd-Aa-wH4\"/>\n                                                                    <constraint firstItem=\"Oc1-jQ-wrY\" firstAttribute=\"height\" secondItem=\"Pc4-ai-AKq\" secondAttribute=\"height\" multiplier=\"0.514286\" id=\"UzQ-sM-a3x\"/>\n                                                                </constraints>\n                                                            </view>\n                                                        </subviews>\n                                                        <constraints>\n                                                            <constraint firstItem=\"yJd-Jb-qnY\" firstAttribute=\"width\" secondItem=\"xMO-F4-tcZ\" secondAttribute=\"width\" multiplier=\"0.54\" id=\"3oU-mV-kLB\"/>\n                                                        </constraints>\n                                                    </stackView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"xMO-F4-tcZ\" secondAttribute=\"trailing\" id=\"Mbh-N1-Elc\"/>\n                                                    <constraint firstItem=\"xMO-F4-tcZ\" firstAttribute=\"leading\" secondItem=\"oBy-GA-5e4\" secondAttribute=\"leading\" id=\"sfL-BX-wdu\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"xMO-F4-tcZ\" secondAttribute=\"bottom\" id=\"tYn-ap-fKN\"/>\n                                                    <constraint firstItem=\"xMO-F4-tcZ\" firstAttribute=\"top\" secondItem=\"oBy-GA-5e4\" secondAttribute=\"top\" id=\"wxS-sw-PLe\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"3wo-Mt-fmw\" firstAttribute=\"height\" secondItem=\"ff8-UG-dZY\" secondAttribute=\"height\" multiplier=\"0.26\" id=\"31v-8L-E1V\"/>\n                                            <constraint firstItem=\"Gfs-SL-cU8\" firstAttribute=\"height\" secondItem=\"ff8-UG-dZY\" secondAttribute=\"height\" multiplier=\"0.19\" id=\"8YV-51-stU\"/>\n                                            <constraint firstItem=\"h7N-Pp-L64\" firstAttribute=\"height\" secondItem=\"ff8-UG-dZY\" secondAttribute=\"height\" multiplier=\"0.18\" id=\"YC4-4v-Gq5\"/>\n                                            <constraint firstItem=\"1dY-ve-QjQ\" firstAttribute=\"height\" secondItem=\"ff8-UG-dZY\" secondAttribute=\"height\" multiplier=\"0.26\" id=\"a08-IZ-HaA\"/>\n                                        </constraints>\n                                    </stackView>\n                                </subviews>\n                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <constraints>\n                                    <constraint firstItem=\"ff8-UG-dZY\" firstAttribute=\"top\" secondItem=\"QUw-Ge-iDz\" secondAttribute=\"top\" id=\"4Tk-g2-bYi\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"ff8-UG-dZY\" secondAttribute=\"trailing\" id=\"OEX-0l-ZV9\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"ff8-UG-dZY\" secondAttribute=\"bottom\" id=\"Ozr-bn-Sr4\"/>\n                                    <constraint firstItem=\"ff8-UG-dZY\" firstAttribute=\"leading\" secondItem=\"QUw-Ge-iDz\" secondAttribute=\"leading\" id=\"eRb-Ek-h2p\"/>\n                                    <constraint firstAttribute=\"width\" secondItem=\"QUw-Ge-iDz\" secondAttribute=\"height\" multiplier=\"333:319\" id=\"lCq-H1-EnB\"/>\n                                </constraints>\n                            </view>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ctr-KM-6Ut\">\n                                <rect key=\"frame\" x=\"277\" y=\"32\" width=\"100\" height=\"44\"/>\n                                <subviews>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Close\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6OJ-eW-yDo\">\n                                        <rect key=\"frame\" x=\"27.333333333333311\" y=\"11.333333333333337\" width=\"45.666666666666657\" height=\"21.666666666666671\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"18\"/>\n                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                </subviews>\n                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"100\" id=\"Bsh-0g-fXQ\"/>\n                                    <constraint firstAttribute=\"width\" secondItem=\"Ctr-KM-6Ut\" secondAttribute=\"height\" multiplier=\"50:22\" id=\"ESh-92-bPK\"/>\n                                    <constraint firstItem=\"6OJ-eW-yDo\" firstAttribute=\"centerY\" secondItem=\"Ctr-KM-6Ut\" secondAttribute=\"centerY\" id=\"PrN-Mb-Uic\"/>\n                                    <constraint firstItem=\"6OJ-eW-yDo\" firstAttribute=\"centerX\" secondItem=\"Ctr-KM-6Ut\" secondAttribute=\"centerX\" id=\"pgC-R6-LlR\"/>\n                                </constraints>\n                            </view>\n                        </subviews>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"wgW-d3-5fz\" firstAttribute=\"top\" secondItem=\"rht-LB-R9i\" secondAttribute=\"bottom\" constant=\"-59\" id=\"6f7-LP-Ihp\"/>\n                            <constraint firstItem=\"Ctr-KM-6Ut\" firstAttribute=\"top\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"top\" constant=\"32\" id=\"Bol-Ru-e6K\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"wgW-d3-5fz\" secondAttribute=\"trailing\" id=\"HMG-cp-bRW\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"Ctr-KM-6Ut\" secondAttribute=\"trailing\" constant=\"16\" id=\"JZQ-FF-aoa\"/>\n                            <constraint firstItem=\"QOw-8g-xS4\" firstAttribute=\"top\" secondItem=\"wgW-d3-5fz\" secondAttribute=\"bottom\" constant=\"-34\" id=\"WnG-Mg-LVp\"/>\n                            <constraint firstItem=\"QUw-Ge-iDz\" firstAttribute=\"centerY\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"centerY\" id=\"Y3h-u9-xzN\"/>\n                            <constraint firstItem=\"QUw-Ge-iDz\" firstAttribute=\"centerX\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"centerX\" id=\"afw-mb-UG6\"/>\n                            <constraint firstItem=\"wgW-d3-5fz\" firstAttribute=\"leading\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"leading\" id=\"e5S-5t-BVG\"/>\n                            <constraint firstItem=\"QUw-Ge-iDz\" firstAttribute=\"width\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"width\" multiplier=\"0.847328\" id=\"hg8-ih-VVW\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"852\"/>\n                    <connections>\n                        <outlet property=\"tfCloudName\" destination=\"Dyc-Pr-WD2\" id=\"LUl-fU-ezO\"/>\n                        <outlet property=\"vwCantFindCloud\" destination=\"oBy-GA-5e4\" id=\"2hn-YR-hUS\"/>\n                        <outlet property=\"vwClose\" destination=\"Ctr-KM-6Ut\" id=\"gCQ-Vo-mra\"/>\n                        <outlet property=\"vwGetStarted\" destination=\"h7N-Pp-L64\" id=\"Sbl-df-dVb\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Ief-a0-LHa\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"112.21374045801527\" y=\"-2.1126760563380285\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"question_mark\" width=\"18\" height=\"18\"/>\n        <image name=\"splash_without_logo\" width=\"786\" height=\"1704\"/>\n        <namedColor name=\"gradient-first\">\n            <color red=\"0.20392156862745098\" green=\"0.28235294117647058\" blue=\"0.77254901960784317\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Video/Social/VideoSocialOverlays.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Video Social Overlays Controller-->\n        <scene sceneID=\"s0d-6b-0kx\">\n            <objects>\n                <viewController storyboardIdentifier=\"VideoSocialOverlaysController\" id=\"Y6W-OH-hqX\" customClass=\"VideoSocialOverlaysController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"FK3-M2-4rq\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"bYb-Rn-gOi\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5EZ-qb-Rvc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ovK-HP-aNP\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"382\" width=\"393\" height=\"400\"/>\n                                <subviews>\n                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" distribution=\"fillEqually\" spacing=\"16\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nvF-dV-h2Y\">\n                                        <rect key=\"frame\" x=\"305\" y=\"0.0\" width=\"80\" height=\"400\"/>\n                                        <subviews>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ghN-pa-uch\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"80\" height=\"67.333333333333329\"/>\n                                                <subviews>\n                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_social_icon\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gpW-vF-rUx\">\n                                                        <rect key=\"frame\" x=\"15\" y=\"8.6666666666666856\" width=\"50\" height=\"50\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" constant=\"50\" id=\"Lqk-gS-g58\"/>\n                                                            <constraint firstAttribute=\"width\" secondItem=\"gpW-vF-rUx\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"tw7-RH-ymK\"/>\n                                                        </constraints>\n                                                    </imageView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"gpW-vF-rUx\" firstAttribute=\"centerY\" secondItem=\"ghN-pa-uch\" secondAttribute=\"centerY\" id=\"AIw-c6-LhG\"/>\n                                                    <constraint firstItem=\"gpW-vF-rUx\" firstAttribute=\"centerX\" secondItem=\"ghN-pa-uch\" secondAttribute=\"centerX\" id=\"Ovd-yQ-xXL\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mhE-tX-vpY\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"83.333333333333314\" width=\"80\" height=\"67\"/>\n                                                <subviews>\n                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"center\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_like\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Gph-eN-7Ss\">\n                                                        <rect key=\"frame\" x=\"-15.666666666666686\" y=\"-22\" width=\"111.33333333333333\" height=\"111\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" secondItem=\"Gph-eN-7Ss\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"Neu-wi-xID\"/>\n                                                        </constraints>\n                                                    </imageView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"Gph-eN-7Ss\" firstAttribute=\"centerY\" secondItem=\"mhE-tX-vpY\" secondAttribute=\"centerY\" id=\"2bG-aX-9Dv\"/>\n                                                    <constraint firstItem=\"Gph-eN-7Ss\" firstAttribute=\"width\" secondItem=\"mhE-tX-vpY\" secondAttribute=\"width\" multiplier=\"1.38889\" id=\"ahs-9V-OVU\"/>\n                                                    <constraint firstItem=\"Gph-eN-7Ss\" firstAttribute=\"centerX\" secondItem=\"mhE-tX-vpY\" secondAttribute=\"centerX\" id=\"aym-54-lsg\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6CB-Pf-rv2\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"166.33333333333337\" width=\"80\" height=\"67.333333333333314\"/>\n                                                <subviews>\n                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"center\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_comments\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cGI-4e-SgV\">\n                                                        <rect key=\"frame\" x=\"-15.666666666666686\" y=\"-22\" width=\"111.33333333333333\" height=\"111.33333333333333\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" secondItem=\"cGI-4e-SgV\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"loV-Tk-j27\"/>\n                                                        </constraints>\n                                                    </imageView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"cGI-4e-SgV\" firstAttribute=\"centerX\" secondItem=\"6CB-Pf-rv2\" secondAttribute=\"centerX\" id=\"9qm-EA-RUV\"/>\n                                                    <constraint firstItem=\"cGI-4e-SgV\" firstAttribute=\"centerY\" secondItem=\"6CB-Pf-rv2\" secondAttribute=\"centerY\" id=\"fap-KS-dka\"/>\n                                                    <constraint firstItem=\"cGI-4e-SgV\" firstAttribute=\"width\" secondItem=\"6CB-Pf-rv2\" secondAttribute=\"width\" multiplier=\"1.38889\" id=\"tGj-SV-VwG\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qtf-re-xlr\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"249.66666666666663\" width=\"80\" height=\"67\"/>\n                                                <subviews>\n                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"center\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_share\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sba-VN-LE5\">\n                                                        <rect key=\"frame\" x=\"-15.666666666666686\" y=\"-22\" width=\"111.33333333333333\" height=\"111\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" secondItem=\"sba-VN-LE5\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"g0i-jP-8mN\"/>\n                                                        </constraints>\n                                                    </imageView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"sba-VN-LE5\" firstAttribute=\"centerY\" secondItem=\"qtf-re-xlr\" secondAttribute=\"centerY\" id=\"2BS-xX-QYm\"/>\n                                                    <constraint firstItem=\"sba-VN-LE5\" firstAttribute=\"centerX\" secondItem=\"qtf-re-xlr\" secondAttribute=\"centerX\" id=\"Ohu-Uj-DfY\"/>\n                                                    <constraint firstItem=\"sba-VN-LE5\" firstAttribute=\"width\" secondItem=\"qtf-re-xlr\" secondAttribute=\"width\" multiplier=\"1.38889\" id=\"WBg-Fd-Ska\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"i3n-7G-2e9\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"332.66666666666663\" width=\"80\" height=\"67.333333333333314\"/>\n                                                <subviews>\n                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_music\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"IrE-EP-plp\">\n                                                        <rect key=\"frame\" x=\"-10\" y=\"0.0\" width=\"80\" height=\"70\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" constant=\"80\" id=\"IEX-02-Dcw\"/>\n                                                            <constraint firstAttribute=\"width\" secondItem=\"IrE-EP-plp\" secondAttribute=\"height\" multiplier=\"8:7\" id=\"pla-1T-RLH\"/>\n                                                        </constraints>\n                                                    </imageView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"IrE-EP-plp\" firstAttribute=\"top\" secondItem=\"i3n-7G-2e9\" secondAttribute=\"top\" id=\"uvo-HI-a7r\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"IrE-EP-plp\" firstAttribute=\"centerX\" secondItem=\"sba-VN-LE5\" secondAttribute=\"centerX\" constant=\"-10\" id=\"jz8-zK-tzw\"/>\n                                            <constraint firstAttribute=\"width\" secondItem=\"nvF-dV-h2Y\" secondAttribute=\"height\" multiplier=\"1:5\" id=\"r4K-Gf-6vA\"/>\n                                        </constraints>\n                                    </stackView>\n                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacing=\"6\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8Ne-oA-H0F\">\n                                        <rect key=\"frame\" x=\"16\" y=\"285\" width=\"281\" height=\"115\"/>\n                                        <subviews>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NLM-pr-mSc\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"281\" height=\"24\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"@Appdinary\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Q6c-8V-iCw\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"2.3333333333333712\" width=\"89\" height=\"19.333333333333332\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"16\"/>\n                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"Q6c-8V-iCw\" firstAttribute=\"centerY\" secondItem=\"NLM-pr-mSc\" secondAttribute=\"centerY\" id=\"VuJ-cn-Pcb\"/>\n                                                    <constraint firstItem=\"Q6c-8V-iCw\" firstAttribute=\"leading\" secondItem=\"NLM-pr-mSc\" secondAttribute=\"leading\" id=\"qRj-3B-7Lj\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9i5-k1-djf\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"29.999999999999996\" width=\"281\" height=\"41.666666666666657\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" textAlignment=\"natural\" lineBreakMode=\"wordWrap\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tYy-Jj-MoK\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"4\" width=\"281\" height=\"33.666666666666664\"/>\n                                                        <string key=\"text\">Check out the scenes from our annual\ncompany get-together</string>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"tYy-Jj-MoK\" secondAttribute=\"trailing\" id=\"GOJ-B4-jcE\"/>\n                                                    <constraint firstItem=\"tYy-Jj-MoK\" firstAttribute=\"centerY\" secondItem=\"9i5-k1-djf\" secondAttribute=\"centerY\" id=\"K8J-xO-llX\"/>\n                                                    <constraint firstItem=\"tYy-Jj-MoK\" firstAttribute=\"leading\" secondItem=\"9i5-k1-djf\" secondAttribute=\"leading\" id=\"yYp-qt-bI2\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HxR-XK-kvw\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"77.666666666666629\" width=\"281\" height=\"37.333333333333343\"/>\n                                                <subviews>\n                                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"TTS-Ah-FP4\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"281\" height=\"37.333333333333336\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"51m-gh-59A\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"14\" height=\"37.333333333333336\"/>\n                                                                <subviews>\n                                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_note\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0Qd-sX-6eh\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"11.666666666666742\" width=\"14\" height=\"14\"/>\n                                                                        <constraints>\n                                                                            <constraint firstAttribute=\"width\" secondItem=\"0Qd-sX-6eh\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"DpK-SA-aI2\"/>\n                                                                        </constraints>\n                                                                    </imageView>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"0Qd-sX-6eh\" firstAttribute=\"centerY\" secondItem=\"51m-gh-59A\" secondAttribute=\"centerY\" id=\"BXB-5m-AM0\"/>\n                                                                    <constraint firstItem=\"0Qd-sX-6eh\" firstAttribute=\"width\" secondItem=\"51m-gh-59A\" secondAttribute=\"width\" id=\"MQj-Ux-Iu5\"/>\n                                                                    <constraint firstItem=\"0Qd-sX-6eh\" firstAttribute=\"centerX\" secondItem=\"51m-gh-59A\" secondAttribute=\"centerX\" id=\"qEc-6Q-8Jj\"/>\n                                                                </constraints>\n                                                            </view>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"WVt-Bh-WDm\">\n                                                                <rect key=\"frame\" x=\"22\" y=\"0.0\" width=\"259\" height=\"37.333333333333336\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Page name · Original Audio\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ehh-6g-Vj4\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"10\" width=\"259\" height=\"17\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstAttribute=\"trailing\" secondItem=\"ehh-6g-Vj4\" secondAttribute=\"trailing\" id=\"Pk2-Ia-Kao\"/>\n                                                                    <constraint firstItem=\"ehh-6g-Vj4\" firstAttribute=\"leading\" secondItem=\"WVt-Bh-WDm\" secondAttribute=\"leading\" id=\"zoc-h4-lwf\"/>\n                                                                    <constraint firstItem=\"ehh-6g-Vj4\" firstAttribute=\"centerY\" secondItem=\"WVt-Bh-WDm\" secondAttribute=\"centerY\" id=\"zsQ-sZ-kp6\"/>\n                                                                </constraints>\n                                                            </view>\n                                                        </subviews>\n                                                        <constraints>\n                                                            <constraint firstItem=\"51m-gh-59A\" firstAttribute=\"width\" secondItem=\"TTS-Ah-FP4\" secondAttribute=\"width\" multiplier=\"0.05\" id=\"7nL-hc-vKd\"/>\n                                                        </constraints>\n                                                    </stackView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"TTS-Ah-FP4\" firstAttribute=\"leading\" secondItem=\"HxR-XK-kvw\" secondAttribute=\"leading\" id=\"GxN-s1-BOT\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"TTS-Ah-FP4\" secondAttribute=\"trailing\" id=\"b6n-Fe-jF5\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"TTS-Ah-FP4\" secondAttribute=\"bottom\" id=\"gDO-Bl-Nbp\"/>\n                                                    <constraint firstItem=\"TTS-Ah-FP4\" firstAttribute=\"top\" secondItem=\"HxR-XK-kvw\" secondAttribute=\"top\" id=\"xsR-om-vjw\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"9i5-k1-djf\" firstAttribute=\"height\" secondItem=\"8Ne-oA-H0F\" secondAttribute=\"height\" multiplier=\"0.36\" id=\"VCK-Ke-b07\"/>\n                                            <constraint firstAttribute=\"height\" constant=\"115\" id=\"iDQ-OO-RgV\"/>\n                                            <constraint firstItem=\"NLM-pr-mSc\" firstAttribute=\"height\" secondItem=\"8Ne-oA-H0F\" secondAttribute=\"height\" multiplier=\"0.21\" id=\"x82-43-y76\"/>\n                                        </constraints>\n                                    </stackView>\n                                </subviews>\n                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <constraints>\n                                    <constraint firstItem=\"nvF-dV-h2Y\" firstAttribute=\"centerY\" secondItem=\"ovK-HP-aNP\" secondAttribute=\"centerY\" id=\"4RQ-Gf-WkO\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"8Ne-oA-H0F\" secondAttribute=\"bottom\" id=\"MeT-Xd-VGm\"/>\n                                    <constraint firstItem=\"nvF-dV-h2Y\" firstAttribute=\"leading\" secondItem=\"8Ne-oA-H0F\" secondAttribute=\"trailing\" constant=\"8\" id=\"OUV-jN-ZoF\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"nvF-dV-h2Y\" secondAttribute=\"bottom\" id=\"TJX-IX-8MV\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"nvF-dV-h2Y\" secondAttribute=\"trailing\" constant=\"8\" id=\"Xig-eb-0s1\"/>\n                                    <constraint firstAttribute=\"width\" secondItem=\"ovK-HP-aNP\" secondAttribute=\"height\" multiplier=\"393:400\" id=\"gQq-AL-EB6\"/>\n                                    <constraint firstItem=\"8Ne-oA-H0F\" firstAttribute=\"leading\" secondItem=\"ovK-HP-aNP\" secondAttribute=\"leading\" constant=\"16\" id=\"hmq-hD-hWh\"/>\n                                </constraints>\n                            </view>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"ovK-HP-aNP\" firstAttribute=\"width\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"width\" id=\"O7A-db-agB\"/>\n                            <constraint firstItem=\"bYb-Rn-gOi\" firstAttribute=\"top\" secondItem=\"ovK-HP-aNP\" secondAttribute=\"bottom\" constant=\"36\" id=\"j8k-CN-WKF\"/>\n                            <constraint firstItem=\"ovK-HP-aNP\" firstAttribute=\"centerX\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"centerX\" id=\"yYO-pX-yNM\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"852\"/>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Ief-a0-LHa\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"138\" y=\"4\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"tiktok_comments\" width=\"38\" height=\"36\"/>\n        <image name=\"tiktok_like\" width=\"39\" height=\"36\"/>\n        <image name=\"tiktok_music\" width=\"82\" height=\"72\"/>\n        <image name=\"tiktok_note\" width=\"14\" height=\"14\"/>\n        <image name=\"tiktok_share\" width=\"37\" height=\"30\"/>\n        <image name=\"tiktok_social_icon\" width=\"52\" height=\"63\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Video/Video.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"collection view cell content view\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Video View Controller-->\n        <scene sceneID=\"9Q0-Jn-ehZ\">\n            <objects>\n                <viewController storyboardIdentifier=\"VideoViewController\" id=\"GsG-2N-3th\" customClass=\"VideoViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"ydY-gF-lN8\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2UM-8x-hcO\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"59\" width=\"393\" height=\"739\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8hw-Jx-phJ\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"99.666666666666671\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lQV-Nt-863\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"99.666666666666671\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BEs-3q-Vau\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"65\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Video\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"iGy-n5-699\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"10\" width=\"94\" height=\"43\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"semibold\" pointSize=\"36\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"iGy-n5-699\" firstAttribute=\"leading\" secondItem=\"BEs-3q-Vau\" secondAttribute=\"leading\" constant=\"16\" id=\"ssE-od-tCR\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"iGy-n5-699\" secondAttribute=\"bottom\" constant=\"12\" id=\"yko-71-uiP\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hpg-BS-9u8\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"65\" width=\"393\" height=\"34.666666666666657\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xPp-kS-nWB\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"47\" height=\"5\"/>\n                                                                <color key=\"backgroundColor\" name=\"primary\"/>\n                                                                <constraints>\n                                                                    <constraint firstAttribute=\"height\" constant=\"5\" id=\"cl5-y4-lPR\"/>\n                                                                </constraints>\n                                                                <userDefinedRuntimeAttributes>\n                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                        <real key=\"value\" value=\"2.5\"/>\n                                                                    </userDefinedRuntimeAttribute>\n                                                                </userDefinedRuntimeAttributes>\n                                                            </view>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"xPp-kS-nWB\" firstAttribute=\"width\" secondItem=\"hpg-BS-9u8\" secondAttribute=\"width\" multiplier=\"0.119593\" id=\"07U-NF-ygY\"/>\n                                                            <constraint firstItem=\"xPp-kS-nWB\" firstAttribute=\"top\" secondItem=\"hpg-BS-9u8\" secondAttribute=\"top\" id=\"44z-WE-3ir\"/>\n                                                            <constraint firstItem=\"xPp-kS-nWB\" firstAttribute=\"leading\" secondItem=\"hpg-BS-9u8\" secondAttribute=\"leading\" constant=\"16\" id=\"9SH-oC-vue\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"BEs-3q-Vau\" firstAttribute=\"height\" secondItem=\"lQV-Nt-863\" secondAttribute=\"height\" multiplier=\"0.65\" id=\"kHw-Ol-IMs\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"lQV-Nt-863\" secondAttribute=\"trailing\" id=\"VGw-Q4-kkc\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"lQV-Nt-863\" secondAttribute=\"bottom\" id=\"WIl-Ck-qFD\"/>\n                                            <constraint firstItem=\"lQV-Nt-863\" firstAttribute=\"leading\" secondItem=\"8hw-Jx-phJ\" secondAttribute=\"leading\" id=\"XRh-c2-zRF\"/>\n                                            <constraint firstItem=\"lQV-Nt-863\" firstAttribute=\"top\" secondItem=\"8hw-Jx-phJ\" secondAttribute=\"top\" id=\"zKM-Rb-fDu\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"z1T-66-db4\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"99.666666666666657\" width=\"393\" height=\"68.666666666666657\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Hwe-Ys-Cq7\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"68.666666666666671\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"e2A-Kj-fc8\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"29.666666666666668\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Video Player\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"52c-3z-xDR\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"4\" width=\"103\" height=\"21.666666666666668\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"52c-3z-xDR\" firstAttribute=\"leading\" secondItem=\"e2A-Kj-fc8\" secondAttribute=\"leading\" constant=\"16\" id=\"0oz-Fb-lM0\"/>\n                                                            <constraint firstItem=\"52c-3z-xDR\" firstAttribute=\"centerY\" secondItem=\"e2A-Kj-fc8\" secondAttribute=\"centerY\" id=\"ubO-VF-DJ5\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cGJ-Bl-d7U\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"29.666666666666686\" width=\"393\" height=\"39\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"watch and enjoy videos with our user-friendly video player.\" textAlignment=\"natural\" lineBreakMode=\"wordWrap\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"L6q-L7-Awz\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"0.33333333333331439\" width=\"361\" height=\"38.333333333333336\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"16\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"L6q-L7-Awz\" firstAttribute=\"centerY\" secondItem=\"cGJ-Bl-d7U\" secondAttribute=\"centerY\" id=\"6zW-Ao-NO5\"/>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"L6q-L7-Awz\" secondAttribute=\"trailing\" constant=\"16\" id=\"YTS-8f-O40\"/>\n                                                            <constraint firstItem=\"L6q-L7-Awz\" firstAttribute=\"leading\" secondItem=\"cGJ-Bl-d7U\" secondAttribute=\"leading\" constant=\"16\" id=\"jS5-br-ZIY\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"e2A-Kj-fc8\" firstAttribute=\"height\" secondItem=\"Hwe-Ys-Cq7\" secondAttribute=\"height\" multiplier=\"0.43\" id=\"a4g-cx-w9b\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"Hwe-Ys-Cq7\" secondAttribute=\"bottom\" id=\"1AK-Nv-CxH\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"Hwe-Ys-Cq7\" secondAttribute=\"trailing\" id=\"YJx-Qf-qft\"/>\n                                            <constraint firstItem=\"Hwe-Ys-Cq7\" firstAttribute=\"top\" secondItem=\"z1T-66-db4\" secondAttribute=\"top\" id=\"n2Z-zt-ztK\"/>\n                                            <constraint firstItem=\"Hwe-Ys-Cq7\" firstAttribute=\"leading\" secondItem=\"z1T-66-db4\" secondAttribute=\"leading\" id=\"zSp-dL-z59\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YRK-MB-AVj\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"168.33333333333337\" width=\"393\" height=\"236.66666666666663\"/>\n                                        <subviews>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zbD-De-hCc\">\n                                                <rect key=\"frame\" x=\"18\" y=\"16.333333333333314\" width=\"357\" height=\"204\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" secondItem=\"zbD-De-hCc\" secondAttribute=\"height\" multiplier=\"7:4\" id=\"a3R-mf-fBr\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"zbD-De-hCc\" firstAttribute=\"centerX\" secondItem=\"YRK-MB-AVj\" secondAttribute=\"centerX\" id=\"FdD-DC-pci\"/>\n                                            <constraint firstItem=\"zbD-De-hCc\" firstAttribute=\"centerY\" secondItem=\"YRK-MB-AVj\" secondAttribute=\"centerY\" id=\"HUJ-Nf-XkQ\"/>\n                                            <constraint firstItem=\"zbD-De-hCc\" firstAttribute=\"width\" secondItem=\"YRK-MB-AVj\" secondAttribute=\"width\" multiplier=\"0.908397\" id=\"wff-ay-JsD\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7o0-Pk-dph\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"405\" width=\"393\" height=\"68.666666666666686\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Y96-dH-Z6a\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"68.666666666666671\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"EGw-0w-T00\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"29.666666666666668\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Video Feed\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aCC-PF-qSB\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"4\" width=\"92.666666666666671\" height=\"21.666666666666668\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"aCC-PF-qSB\" firstAttribute=\"centerY\" secondItem=\"EGw-0w-T00\" secondAttribute=\"centerY\" id=\"6gE-D6-fJL\"/>\n                                                            <constraint firstItem=\"aCC-PF-qSB\" firstAttribute=\"leading\" secondItem=\"EGw-0w-T00\" secondAttribute=\"leading\" constant=\"16\" id=\"6hP-AL-nfa\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kEt-Gy-Fkb\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"29.666666666666686\" width=\"393\" height=\"39\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Try our social media simulator for an immersive video feed experience\" textAlignment=\"natural\" lineBreakMode=\"wordWrap\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oat-ec-XkP\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"0.33333333333331439\" width=\"361\" height=\"38.333333333333336\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"16\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"oat-ec-XkP\" firstAttribute=\"centerY\" secondItem=\"kEt-Gy-Fkb\" secondAttribute=\"centerY\" id=\"7g8-6d-81A\"/>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"oat-ec-XkP\" secondAttribute=\"trailing\" constant=\"16\" id=\"NhW-qa-dyk\"/>\n                                                            <constraint firstItem=\"oat-ec-XkP\" firstAttribute=\"leading\" secondItem=\"kEt-Gy-Fkb\" secondAttribute=\"leading\" constant=\"16\" id=\"O6R-2x-kx5\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"EGw-0w-T00\" firstAttribute=\"height\" secondItem=\"Y96-dH-Z6a\" secondAttribute=\"height\" multiplier=\"0.43\" id=\"Skk-9f-oYx\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"Y96-dH-Z6a\" secondAttribute=\"bottom\" id=\"L3N-wt-0mW\"/>\n                                            <constraint firstItem=\"Y96-dH-Z6a\" firstAttribute=\"top\" secondItem=\"7o0-Pk-dph\" secondAttribute=\"top\" id=\"Npg-bj-T2R\"/>\n                                            <constraint firstItem=\"Y96-dH-Z6a\" firstAttribute=\"leading\" secondItem=\"7o0-Pk-dph\" secondAttribute=\"leading\" id=\"uK1-Y2-k9y\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"Y96-dH-Z6a\" secondAttribute=\"trailing\" id=\"zCz-Ir-sPt\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5hO-q8-2Co\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"473.66666666666663\" width=\"393\" height=\"265.33333333333337\"/>\n                                        <subviews>\n                                            <collectionView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" dataMode=\"prototypes\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"grZ-CE-4sM\">\n                                                <rect key=\"frame\" x=\"16\" y=\"16.000000000000014\" width=\"377\" height=\"249.33333333333337\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <collectionViewFlowLayout key=\"collectionViewLayout\" scrollDirection=\"horizontal\" minimumLineSpacing=\"10\" minimumInteritemSpacing=\"10\" id=\"7oX-5P-XYL\">\n                                                    <size key=\"itemSize\" width=\"135\" height=\"239\"/>\n                                                    <size key=\"headerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <size key=\"footerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <inset key=\"sectionInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                                </collectionViewFlowLayout>\n                                                <cells>\n                                                    <collectionViewCell opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" reuseIdentifier=\"videoFeedCell\" id=\"BPc-Dp-25t\" customClass=\"VideoFeedCell\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"5.333333333333333\" width=\"135\" height=\"239\"/>\n                                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                        <collectionViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"sM9-VO-PKu\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"135\" height=\"239\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                                            <subviews>\n                                                                <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Hrh-5S-OsJ\" customClass=\"GradientView\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"135\" height=\"239\"/>\n                                                                    <subviews>\n                                                                        <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"T1M-Sv-V6A\">\n                                                                            <rect key=\"frame\" x=\"39\" y=\"84.666666666666671\" width=\"57\" height=\"70.000000000000014\"/>\n                                                                            <constraints>\n                                                                                <constraint firstAttribute=\"height\" constant=\"70.000000000000014\" id=\"4cF-5r-PB8\"/>\n                                                                                <constraint firstAttribute=\"width\" secondItem=\"T1M-Sv-V6A\" secondAttribute=\"height\" multiplier=\"57:70\" id=\"HTF-cc-cZC\"/>\n                                                                            </constraints>\n                                                                        </imageView>\n                                                                    </subviews>\n                                                                    <color key=\"backgroundColor\" systemColor=\"labelColor\"/>\n                                                                    <constraints>\n                                                                        <constraint firstItem=\"T1M-Sv-V6A\" firstAttribute=\"centerY\" secondItem=\"Hrh-5S-OsJ\" secondAttribute=\"centerY\" id=\"rdl-JX-Oxx\"/>\n                                                                        <constraint firstItem=\"T1M-Sv-V6A\" firstAttribute=\"centerX\" secondItem=\"Hrh-5S-OsJ\" secondAttribute=\"centerX\" id=\"y0R-nA-qBz\"/>\n                                                                    </constraints>\n                                                                    <userDefinedRuntimeAttributes>\n                                                                        <userDefinedRuntimeAttribute type=\"color\" keyPath=\"firstColor\">\n                                                                            <color key=\"value\" name=\"gradient-first\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"color\" keyPath=\"secondColor\">\n                                                                            <color key=\"value\" name=\"gradient-second\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                            <integer key=\"value\" value=\"8\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                    </userDefinedRuntimeAttributes>\n                                                                </view>\n                                                            </subviews>\n                                                            <constraints>\n                                                                <constraint firstItem=\"Hrh-5S-OsJ\" firstAttribute=\"leading\" secondItem=\"sM9-VO-PKu\" secondAttribute=\"leading\" id=\"42i-4j-HGe\"/>\n                                                                <constraint firstAttribute=\"trailing\" secondItem=\"Hrh-5S-OsJ\" secondAttribute=\"trailing\" id=\"4fb-i8-mEB\"/>\n                                                                <constraint firstItem=\"Hrh-5S-OsJ\" firstAttribute=\"top\" secondItem=\"sM9-VO-PKu\" secondAttribute=\"top\" id=\"9zQ-J0-jfl\"/>\n                                                                <constraint firstAttribute=\"bottom\" secondItem=\"Hrh-5S-OsJ\" secondAttribute=\"bottom\" id=\"Sg9-47-y4H\"/>\n                                                            </constraints>\n                                                        </collectionViewCellContentView>\n                                                        <connections>\n                                                            <outlet property=\"ivMain\" destination=\"T1M-Sv-V6A\" id=\"qeZ-cr-cUz\"/>\n                                                            <outlet property=\"vwGradientView\" destination=\"Hrh-5S-OsJ\" id=\"zby-KJ-qxf\"/>\n                                                        </connections>\n                                                    </collectionViewCell>\n                                                </cells>\n                                            </collectionView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"grZ-CE-4sM\" secondAttribute=\"trailing\" id=\"8yl-5n-Tgy\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"grZ-CE-4sM\" secondAttribute=\"bottom\" id=\"C1j-7B-pU4\"/>\n                                            <constraint firstItem=\"grZ-CE-4sM\" firstAttribute=\"top\" secondItem=\"5hO-q8-2Co\" secondAttribute=\"top\" constant=\"16\" id=\"eNn-4z-gbJ\"/>\n                                            <constraint firstItem=\"grZ-CE-4sM\" firstAttribute=\"leading\" secondItem=\"5hO-q8-2Co\" secondAttribute=\"leading\" constant=\"16\" id=\"iZ5-NR-hrN\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"z1T-66-db4\" firstAttribute=\"height\" secondItem=\"2UM-8x-hcO\" secondAttribute=\"height\" multiplier=\"0.093\" id=\"RYb-ac-LpE\"/>\n                                    <constraint firstItem=\"7o0-Pk-dph\" firstAttribute=\"height\" secondItem=\"2UM-8x-hcO\" secondAttribute=\"height\" multiplier=\"0.093105\" id=\"Txa-wF-0Qv\"/>\n                                    <constraint firstItem=\"8hw-Jx-phJ\" firstAttribute=\"height\" secondItem=\"2UM-8x-hcO\" secondAttribute=\"height\" multiplier=\"0.135\" id=\"k8O-7s-VCP\"/>\n                                    <constraint firstItem=\"YRK-MB-AVj\" firstAttribute=\"height\" secondItem=\"2UM-8x-hcO\" secondAttribute=\"height\" multiplier=\"0.32\" id=\"r2u-Wi-bbi\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"wmg-e9-HUc\"/>\n                        <color key=\"backgroundColor\" name=\"surface\"/>\n                        <constraints>\n                            <constraint firstItem=\"2UM-8x-hcO\" firstAttribute=\"bottom\" secondItem=\"wmg-e9-HUc\" secondAttribute=\"bottom\" constant=\"-20\" id=\"Box-g2-dai\"/>\n                            <constraint firstItem=\"wmg-e9-HUc\" firstAttribute=\"top\" secondItem=\"2UM-8x-hcO\" secondAttribute=\"top\" id=\"CCi-nA-CYD\"/>\n                            <constraint firstItem=\"wmg-e9-HUc\" firstAttribute=\"trailing\" secondItem=\"2UM-8x-hcO\" secondAttribute=\"trailing\" id=\"OKB-Bc-kDv\"/>\n                            <constraint firstItem=\"2UM-8x-hcO\" firstAttribute=\"leading\" secondItem=\"wmg-e9-HUc\" secondAttribute=\"leading\" id=\"e39-nQ-7sj\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"852\"/>\n                    <connections>\n                        <outlet property=\"cvVideoFeed\" destination=\"grZ-CE-4sM\" id=\"jWi-WY-SVG\"/>\n                        <outlet property=\"vwVideoView\" destination=\"zbD-De-hCc\" id=\"wad-Fb-CPH\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"f3w-ve-Foh\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"139\" y=\"-2\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"tiktok\" width=\"447\" height=\"512.57000732421875\"/>\n        <namedColor name=\"gradient-first\">\n            <color red=\"0.20392156862745098\" green=\"0.28235294117647058\" blue=\"0.77254901960784317\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"gradient-second\">\n            <color red=\"0.15686274509803921\" green=\"0.73333333333333328\" blue=\"0.98039215686274506\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"primary\">\n            <color red=\"0.27450980392156865\" green=\"0.59607843137254901\" blue=\"0.96862745098039216\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"surface\">\n            <color red=\"0.12549019607843137\" green=\"0.14117647058823529\" blue=\"0.17647058823529413\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <systemColor name=\"labelColor\">\n            <color white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Video/VideoFeed.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Video Feed Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController storyboardIdentifier=\"VideoFeedController\" id=\"BYZ-38-t0r\" customClass=\"VideoFeedController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"akf-JS-pz8\">\n                                <rect key=\"frame\" x=\"16\" y=\"75\" width=\"28\" height=\"28\"/>\n                                <subviews>\n                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"center\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"back_arrow\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tJm-6d-xl9\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"28\" height=\"28\"/>\n                                    </imageView>\n                                </subviews>\n                                <color key=\"backgroundColor\" name=\"secondary\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"28\" id=\"1hz-id-MhY\"/>\n                                    <constraint firstItem=\"tJm-6d-xl9\" firstAttribute=\"width\" secondItem=\"akf-JS-pz8\" secondAttribute=\"width\" id=\"H7u-s5-OcI\"/>\n                                    <constraint firstAttribute=\"width\" secondItem=\"akf-JS-pz8\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"NqV-j9-fat\"/>\n                                    <constraint firstItem=\"tJm-6d-xl9\" firstAttribute=\"height\" secondItem=\"akf-JS-pz8\" secondAttribute=\"height\" id=\"VmK-Vf-duD\"/>\n                                    <constraint firstItem=\"tJm-6d-xl9\" firstAttribute=\"centerY\" secondItem=\"akf-JS-pz8\" secondAttribute=\"centerY\" id=\"awJ-UA-wMR\"/>\n                                    <constraint firstItem=\"tJm-6d-xl9\" firstAttribute=\"centerX\" secondItem=\"akf-JS-pz8\" secondAttribute=\"centerX\" id=\"n4J-3u-3mc\"/>\n                                </constraints>\n                                <userDefinedRuntimeAttributes>\n                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                        <integer key=\"value\" value=\"14\"/>\n                                    </userDefinedRuntimeAttribute>\n                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBounds\" value=\"YES\"/>\n                                </userDefinedRuntimeAttributes>\n                            </view>\n                            <containerView opaque=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lDy-hf-UP7\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"765\"/>\n                                <connections>\n                                    <segue destination=\"G5A-L0-4yi\" kind=\"embed\" id=\"Rz6-nt-p2b\"/>\n                                </connections>\n                            </containerView>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XXM-84-0yJ\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"765\" width=\"393\" height=\"87\"/>\n                                <subviews>\n                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" spacing=\"24\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jX1-RV-nJu\">\n                                        <rect key=\"frame\" x=\"16\" y=\"8\" width=\"361\" height=\"45\"/>\n                                        <subviews>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ndI-zz-g6e\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"45\"/>\n                                                <subviews>\n                                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dSb-YX-Oeb\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"45\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4YJ-3b-1WK\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"25.333333333333332\"/>\n                                                                <subviews>\n                                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_home\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VBQ-Vl-q6I\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"25.333333333333332\"/>\n                                                                    </imageView>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"VBQ-Vl-q6I\" firstAttribute=\"top\" secondItem=\"4YJ-3b-1WK\" secondAttribute=\"top\" id=\"25j-mW-vKs\"/>\n                                                                    <constraint firstAttribute=\"trailing\" secondItem=\"VBQ-Vl-q6I\" secondAttribute=\"trailing\" id=\"NUI-ue-O4d\"/>\n                                                                    <constraint firstAttribute=\"bottom\" secondItem=\"VBQ-Vl-q6I\" secondAttribute=\"bottom\" id=\"Q1A-Dd-yby\"/>\n                                                                    <constraint firstItem=\"VBQ-Vl-q6I\" firstAttribute=\"leading\" secondItem=\"4YJ-3b-1WK\" secondAttribute=\"leading\" id=\"QcZ-8Q-Wfe\"/>\n                                                                </constraints>\n                                                            </view>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Tcy-MS-Azq\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"25.333333333333371\" width=\"39.666666666666664\" height=\"19.666666666666671\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Home\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ugu-3Z-gsX\">\n                                                                        <rect key=\"frame\" x=\"5.6666666666666696\" y=\"3.6666666666666288\" width=\"28.333333333333329\" height=\"12\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"10\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"ugu-3Z-gsX\" firstAttribute=\"centerX\" secondItem=\"Tcy-MS-Azq\" secondAttribute=\"centerX\" id=\"Shs-E9-0Qu\"/>\n                                                                    <constraint firstItem=\"ugu-3Z-gsX\" firstAttribute=\"centerY\" secondItem=\"Tcy-MS-Azq\" secondAttribute=\"centerY\" id=\"YVZ-uc-Kiu\"/>\n                                                                </constraints>\n                                                            </view>\n                                                        </subviews>\n                                                        <constraints>\n                                                            <constraint firstItem=\"4YJ-3b-1WK\" firstAttribute=\"height\" secondItem=\"dSb-YX-Oeb\" secondAttribute=\"height\" multiplier=\"0.56\" id=\"H3V-Qg-6CS\"/>\n                                                        </constraints>\n                                                    </stackView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"dSb-YX-Oeb\" firstAttribute=\"top\" secondItem=\"ndI-zz-g6e\" secondAttribute=\"top\" id=\"2fw-Aj-Hbg\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"dSb-YX-Oeb\" secondAttribute=\"trailing\" id=\"bHO-o0-kDx\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"dSb-YX-Oeb\" secondAttribute=\"bottom\" id=\"oSt-3Y-THx\"/>\n                                                    <constraint firstItem=\"dSb-YX-Oeb\" firstAttribute=\"leading\" secondItem=\"ndI-zz-g6e\" secondAttribute=\"leading\" id=\"xjX-Wo-2Do\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"8gG-t7-cSg\">\n                                                <rect key=\"frame\" x=\"63.666666666666671\" y=\"0.0\" width=\"39.666666666666671\" height=\"45\"/>\n                                                <subviews>\n                                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lMH-qq-LWV\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"45\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9ah-7C-K3z\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"25.333333333333332\"/>\n                                                                <subviews>\n                                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_discover\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"pSU-aw-tKp\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"25.333333333333332\"/>\n                                                                    </imageView>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"pSU-aw-tKp\" firstAttribute=\"leading\" secondItem=\"9ah-7C-K3z\" secondAttribute=\"leading\" id=\"5Gs-5x-L7u\"/>\n                                                                    <constraint firstItem=\"pSU-aw-tKp\" firstAttribute=\"top\" secondItem=\"9ah-7C-K3z\" secondAttribute=\"top\" id=\"D8u-NO-eyx\"/>\n                                                                    <constraint firstAttribute=\"trailing\" secondItem=\"pSU-aw-tKp\" secondAttribute=\"trailing\" id=\"M5X-xD-y4t\"/>\n                                                                    <constraint firstAttribute=\"bottom\" secondItem=\"pSU-aw-tKp\" secondAttribute=\"bottom\" id=\"ra2-0A-rbo\"/>\n                                                                </constraints>\n                                                            </view>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XHY-vN-jRT\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"25.333333333333371\" width=\"39.666666666666664\" height=\"19.666666666666671\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Discover\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mwY-6x-1bE\">\n                                                                        <rect key=\"frame\" x=\"-1\" y=\"3.6666666666666288\" width=\"42\" height=\"12\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"10\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"mwY-6x-1bE\" firstAttribute=\"centerX\" secondItem=\"XHY-vN-jRT\" secondAttribute=\"centerX\" id=\"KuW-dU-7CC\"/>\n                                                                    <constraint firstItem=\"mwY-6x-1bE\" firstAttribute=\"centerY\" secondItem=\"XHY-vN-jRT\" secondAttribute=\"centerY\" id=\"rG0-Ba-wLv\"/>\n                                                                </constraints>\n                                                            </view>\n                                                        </subviews>\n                                                        <constraints>\n                                                            <constraint firstItem=\"9ah-7C-K3z\" firstAttribute=\"height\" secondItem=\"lMH-qq-LWV\" secondAttribute=\"height\" multiplier=\"0.56\" id=\"ohb-B3-npM\"/>\n                                                        </constraints>\n                                                    </stackView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"lMH-qq-LWV\" secondAttribute=\"trailing\" id=\"ClS-qb-Eua\"/>\n                                                    <constraint firstItem=\"lMH-qq-LWV\" firstAttribute=\"top\" secondItem=\"8gG-t7-cSg\" secondAttribute=\"top\" id=\"HwN-G9-0Lb\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"lMH-qq-LWV\" secondAttribute=\"bottom\" id=\"hdY-Rm-MHZ\"/>\n                                                    <constraint firstItem=\"lMH-qq-LWV\" firstAttribute=\"leading\" secondItem=\"8gG-t7-cSg\" secondAttribute=\"leading\" id=\"rrD-q0-kUI\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"kIJ-Sn-5ou\">\n                                                <rect key=\"frame\" x=\"127.33333333333334\" y=\"0.0\" width=\"106.33333333333334\" height=\"45\"/>\n                                                <subviews>\n                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_bar_icon\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LQo-fw-9gI\">\n                                                        <rect key=\"frame\" x=\"34.666666666666657\" y=\"10.666666666666631\" width=\"37\" height=\"23.666666666666671\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"width\" secondItem=\"LQo-fw-9gI\" secondAttribute=\"height\" multiplier=\"47:30\" id=\"DHP-Ac-dnv\"/>\n                                                        </constraints>\n                                                    </imageView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"LQo-fw-9gI\" firstAttribute=\"centerY\" secondItem=\"kIJ-Sn-5ou\" secondAttribute=\"centerY\" id=\"klg-nt-tVT\"/>\n                                                    <constraint firstItem=\"LQo-fw-9gI\" firstAttribute=\"width\" secondItem=\"kIJ-Sn-5ou\" secondAttribute=\"width\" multiplier=\"0.346988\" id=\"sPI-Qh-1Re\"/>\n                                                    <constraint firstItem=\"LQo-fw-9gI\" firstAttribute=\"centerX\" secondItem=\"kIJ-Sn-5ou\" secondAttribute=\"centerX\" id=\"xPw-L0-d0c\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2ZC-kj-Bnd\">\n                                                <rect key=\"frame\" x=\"257.66666666666669\" y=\"0.0\" width=\"39.666666666666686\" height=\"45\"/>\n                                                <subviews>\n                                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vn1-Ty-1z2\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"45\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zFy-y3-pYj\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"25.333333333333332\"/>\n                                                                <subviews>\n                                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_inbox\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZTj-7p-H27\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"25.333333333333332\"/>\n                                                                    </imageView>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"ZTj-7p-H27\" firstAttribute=\"top\" secondItem=\"zFy-y3-pYj\" secondAttribute=\"top\" id=\"3oA-Jp-JEn\"/>\n                                                                    <constraint firstItem=\"ZTj-7p-H27\" firstAttribute=\"leading\" secondItem=\"zFy-y3-pYj\" secondAttribute=\"leading\" id=\"Cb1-aG-QVp\"/>\n                                                                    <constraint firstAttribute=\"trailing\" secondItem=\"ZTj-7p-H27\" secondAttribute=\"trailing\" id=\"Nhm-oq-ApT\"/>\n                                                                    <constraint firstAttribute=\"bottom\" secondItem=\"ZTj-7p-H27\" secondAttribute=\"bottom\" id=\"OCH-Fo-Y8L\"/>\n                                                                </constraints>\n                                                            </view>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4EM-2L-4zi\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"25.333333333333371\" width=\"39.666666666666664\" height=\"19.666666666666671\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Inbox\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Sdv-r8-DxZ\">\n                                                                        <rect key=\"frame\" x=\"6.666666666666627\" y=\"3.6666666666666288\" width=\"26.333333333333329\" height=\"12\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"10\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"Sdv-r8-DxZ\" firstAttribute=\"centerX\" secondItem=\"4EM-2L-4zi\" secondAttribute=\"centerX\" id=\"VlE-mU-h9i\"/>\n                                                                    <constraint firstItem=\"Sdv-r8-DxZ\" firstAttribute=\"centerY\" secondItem=\"4EM-2L-4zi\" secondAttribute=\"centerY\" id=\"xbD-In-Rxp\"/>\n                                                                </constraints>\n                                                            </view>\n                                                        </subviews>\n                                                        <constraints>\n                                                            <constraint firstItem=\"zFy-y3-pYj\" firstAttribute=\"height\" secondItem=\"vn1-Ty-1z2\" secondAttribute=\"height\" multiplier=\"0.56\" id=\"tGn-Eb-yWF\"/>\n                                                        </constraints>\n                                                    </stackView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"vn1-Ty-1z2\" secondAttribute=\"trailing\" id=\"HUE-XX-KSU\"/>\n                                                    <constraint firstItem=\"vn1-Ty-1z2\" firstAttribute=\"leading\" secondItem=\"2ZC-kj-Bnd\" secondAttribute=\"leading\" id=\"P1L-rt-4hb\"/>\n                                                    <constraint firstItem=\"vn1-Ty-1z2\" firstAttribute=\"top\" secondItem=\"2ZC-kj-Bnd\" secondAttribute=\"top\" id=\"biJ-eT-HH4\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"vn1-Ty-1z2\" secondAttribute=\"bottom\" id=\"vgg-tG-tH5\"/>\n                                                </constraints>\n                                            </view>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XrM-dA-8F8\">\n                                                <rect key=\"frame\" x=\"321.33333333333331\" y=\"0.0\" width=\"39.666666666666686\" height=\"45\"/>\n                                                <subviews>\n                                                    <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dyN-9f-4Sr\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"45\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"GKR-sb-6nf\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"25.333333333333332\"/>\n                                                                <subviews>\n                                                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"tiktok_home\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ao2-Do-P2R\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"39.666666666666664\" height=\"25.333333333333332\"/>\n                                                                    </imageView>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstAttribute=\"trailing\" secondItem=\"Ao2-Do-P2R\" secondAttribute=\"trailing\" id=\"ChQ-bD-kNQ\"/>\n                                                                    <constraint firstItem=\"Ao2-Do-P2R\" firstAttribute=\"top\" secondItem=\"GKR-sb-6nf\" secondAttribute=\"top\" id=\"GIu-56-KFW\"/>\n                                                                    <constraint firstItem=\"Ao2-Do-P2R\" firstAttribute=\"leading\" secondItem=\"GKR-sb-6nf\" secondAttribute=\"leading\" id=\"JvK-Jy-OnH\"/>\n                                                                    <constraint firstAttribute=\"bottom\" secondItem=\"Ao2-Do-P2R\" secondAttribute=\"bottom\" id=\"Tlr-Tk-6Mx\"/>\n                                                                </constraints>\n                                                            </view>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PCv-au-gM3\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"25.333333333333371\" width=\"39.666666666666664\" height=\"19.666666666666671\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Me\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uSs-hf-If9\">\n                                                                        <rect key=\"frame\" x=\"12.333333333333371\" y=\"3.6666666666666288\" width=\"15\" height=\"12\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"10\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"uSs-hf-If9\" firstAttribute=\"centerY\" secondItem=\"PCv-au-gM3\" secondAttribute=\"centerY\" id=\"Sz7-gI-xiJ\"/>\n                                                                    <constraint firstItem=\"uSs-hf-If9\" firstAttribute=\"centerX\" secondItem=\"PCv-au-gM3\" secondAttribute=\"centerX\" id=\"Wfr-4a-1kN\"/>\n                                                                </constraints>\n                                                            </view>\n                                                        </subviews>\n                                                        <constraints>\n                                                            <constraint firstItem=\"GKR-sb-6nf\" firstAttribute=\"height\" secondItem=\"dyN-9f-4Sr\" secondAttribute=\"height\" multiplier=\"0.56\" id=\"UuA-9E-ABI\"/>\n                                                        </constraints>\n                                                    </stackView>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"dyN-9f-4Sr\" secondAttribute=\"trailing\" id=\"6hM-9d-Ort\"/>\n                                                    <constraint firstItem=\"dyN-9f-4Sr\" firstAttribute=\"leading\" secondItem=\"XrM-dA-8F8\" secondAttribute=\"leading\" id=\"BUq-YK-FyV\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"dyN-9f-4Sr\" secondAttribute=\"bottom\" id=\"W00-HU-GO6\"/>\n                                                    <constraint firstItem=\"dyN-9f-4Sr\" firstAttribute=\"top\" secondItem=\"XrM-dA-8F8\" secondAttribute=\"top\" id=\"xq6-Iq-r5V\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"ndI-zz-g6e\" firstAttribute=\"width\" secondItem=\"jX1-RV-nJu\" secondAttribute=\"width\" multiplier=\"0.11\" id=\"Vjd-Gs-vda\"/>\n                                            <constraint firstItem=\"8gG-t7-cSg\" firstAttribute=\"width\" secondItem=\"ndI-zz-g6e\" secondAttribute=\"width\" id=\"W20-56-cCF\"/>\n                                            <constraint firstItem=\"2ZC-kj-Bnd\" firstAttribute=\"width\" secondItem=\"8gG-t7-cSg\" secondAttribute=\"width\" id=\"ZVw-ow-mE0\"/>\n                                            <constraint firstAttribute=\"height\" constant=\"45\" id=\"Zbo-ou-u4l\"/>\n                                            <constraint firstItem=\"XrM-dA-8F8\" firstAttribute=\"width\" secondItem=\"ndI-zz-g6e\" secondAttribute=\"width\" id=\"sB0-Yb-Zod\"/>\n                                        </constraints>\n                                    </stackView>\n                                </subviews>\n                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <constraints>\n                                    <constraint firstItem=\"jX1-RV-nJu\" firstAttribute=\"leading\" secondItem=\"XXM-84-0yJ\" secondAttribute=\"leading\" constant=\"16\" id=\"8aV-DV-HOZ\"/>\n                                    <constraint firstItem=\"jX1-RV-nJu\" firstAttribute=\"top\" secondItem=\"XXM-84-0yJ\" secondAttribute=\"top\" constant=\"8\" id=\"NYy-N8-o4S\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"87\" id=\"aOv-cB-OLS\"/>\n                                    <constraint firstItem=\"jX1-RV-nJu\" firstAttribute=\"centerX\" secondItem=\"XXM-84-0yJ\" secondAttribute=\"centerX\" id=\"aay-lb-pfc\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"jX1-RV-nJu\" secondAttribute=\"trailing\" constant=\"16\" id=\"nVA-Ti-AXe\"/>\n                                </constraints>\n                            </view>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"akf-JS-pz8\" firstAttribute=\"top\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"top\" constant=\"16\" id=\"Cm9-MJ-GFX\"/>\n                            <constraint firstItem=\"lDy-hf-UP7\" firstAttribute=\"top\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"top\" constant=\"-59\" id=\"JF6-tu-JE9\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"trailing\" secondItem=\"lDy-hf-UP7\" secondAttribute=\"trailing\" id=\"KDf-w1-qtU\"/>\n                            <constraint firstItem=\"akf-JS-pz8\" firstAttribute=\"leading\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"leading\" constant=\"16\" id=\"KTg-If-Byt\"/>\n                            <constraint firstItem=\"XXM-84-0yJ\" firstAttribute=\"centerX\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"centerX\" id=\"TXx-om-eQW\"/>\n                            <constraint firstItem=\"XXM-84-0yJ\" firstAttribute=\"bottom\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"bottom\" constant=\"34\" id=\"Z1R-g2-dzq\"/>\n                            <constraint firstItem=\"XXM-84-0yJ\" firstAttribute=\"top\" secondItem=\"lDy-hf-UP7\" secondAttribute=\"bottom\" id=\"bFz-T3-CIJ\"/>\n                            <constraint firstItem=\"lDy-hf-UP7\" firstAttribute=\"leading\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"leading\" id=\"gRY-S2-lP4\"/>\n                            <constraint firstItem=\"XXM-84-0yJ\" firstAttribute=\"width\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"width\" id=\"mnJ-HV-wxz\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"vwBack\" destination=\"akf-JS-pz8\" id=\"0YJ-hP-lWY\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-124.42748091603053\" y=\"3.5211267605633805\"/>\n        </scene>\n        <!--Main Page Controller-->\n        <scene sceneID=\"856-lv-rW9\">\n            <objects>\n                <pageViewController storyboardIdentifier=\"MainPageController\" autoresizesArchivedViewToFullSize=\"NO\" wantsFullScreenLayout=\"YES\" transitionStyle=\"scroll\" navigationOrientation=\"vertical\" spineLocation=\"none\" id=\"G5A-L0-4yi\" customClass=\"MainPageController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\"/>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"8Ti-gV-Nx0\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"1001\" y=\"-42\"/>\n        </scene>\n        <!--Video Feed Container Controller-->\n        <scene sceneID=\"7Yq-dJ-mjV\">\n            <objects>\n                <viewController storyboardIdentifier=\"VideoFeedContainerController\" id=\"VV3-ey-OIm\" customClass=\"VideoFeedContainerController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"eAC-AP-eLq\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bdX-UD-HYC\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"59\" width=\"393\" height=\"759\"/>\n                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                            </view>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"FXo-Fd-TuF\"/>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"bdX-UD-HYC\" firstAttribute=\"leading\" secondItem=\"FXo-Fd-TuF\" secondAttribute=\"leading\" id=\"1jB-UV-G1A\"/>\n                            <constraint firstItem=\"FXo-Fd-TuF\" firstAttribute=\"bottom\" secondItem=\"bdX-UD-HYC\" secondAttribute=\"bottom\" id=\"DIe-F6-egO\"/>\n                            <constraint firstItem=\"FXo-Fd-TuF\" firstAttribute=\"trailing\" secondItem=\"bdX-UD-HYC\" secondAttribute=\"trailing\" id=\"Phg-OD-h0t\"/>\n                            <constraint firstItem=\"bdX-UD-HYC\" firstAttribute=\"top\" secondItem=\"FXo-Fd-TuF\" secondAttribute=\"top\" id=\"Xqe-Ct-J48\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"vwFeedContainer\" destination=\"bdX-UD-HYC\" id=\"H4X-Jk-cmv\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"9zZ-A2-mx8\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"1870.9923664122136\" y=\"-8.4507042253521139\"/>\n        </scene>\n        <!--Video Feed View Controller-->\n        <scene sceneID=\"GeK-Ko-Nfx\">\n            <objects>\n                <viewController storyboardIdentifier=\"VideoFeedViewController\" id=\"Skc-hd-Wgq\" customClass=\"VideoFeedViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"NdB-AX-Tec\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ip7-73-0Cg\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"48M-ah-ajH\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                    </view>\n                                </subviews>\n                                <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                                <constraints>\n                                    <constraint firstItem=\"48M-ah-ajH\" firstAttribute=\"top\" secondItem=\"ip7-73-0Cg\" secondAttribute=\"top\" id=\"Oyf-lC-ode\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"48M-ah-ajH\" secondAttribute=\"bottom\" id=\"Px3-lw-pf6\"/>\n                                    <constraint firstItem=\"48M-ah-ajH\" firstAttribute=\"leading\" secondItem=\"ip7-73-0Cg\" secondAttribute=\"leading\" id=\"QCH-Vp-q87\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"48M-ah-ajH\" secondAttribute=\"trailing\" id=\"qta-Ig-gHu\"/>\n                                </constraints>\n                            </view>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"Szu-IH-f8m\"/>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"Szu-IH-f8m\" firstAttribute=\"bottom\" secondItem=\"ip7-73-0Cg\" secondAttribute=\"bottom\" constant=\"-34\" id=\"H8f-pb-jnv\"/>\n                            <constraint firstItem=\"Szu-IH-f8m\" firstAttribute=\"trailing\" secondItem=\"ip7-73-0Cg\" secondAttribute=\"trailing\" id=\"Q8C-jf-fxf\"/>\n                            <constraint firstItem=\"ip7-73-0Cg\" firstAttribute=\"leading\" secondItem=\"Szu-IH-f8m\" secondAttribute=\"leading\" id=\"ffE-Vg-oi9\"/>\n                            <constraint firstItem=\"ip7-73-0Cg\" firstAttribute=\"top\" secondItem=\"Szu-IH-f8m\" secondAttribute=\"top\" constant=\"-59\" id=\"gtS-KT-j9b\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"vwVideoOverlay\" destination=\"48M-ah-ajH\" id=\"ATm-48-mqD\"/>\n                        <outlet property=\"vwVideoView\" destination=\"ip7-73-0Cg\" id=\"nAO-cN-7xw\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"5Da-3f-SIC\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"2746\" y=\"4\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"back_arrow\" width=\"12\" height=\"12\"/>\n        <image name=\"tiktok_bar_icon\" width=\"49\" height=\"30\"/>\n        <image name=\"tiktok_discover\" width=\"23\" height=\"23\"/>\n        <image name=\"tiktok_home\" width=\"26\" height=\"23\"/>\n        <image name=\"tiktok_inbox\" width=\"22\" height=\"22\"/>\n        <namedColor name=\"secondary\">\n            <color red=\"0.24705882352941178\" green=\"0.27843137254901962\" blue=\"0.35294117647058826\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Widgets/ImageWidget.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Image Widget View Controller-->\n        <scene sceneID=\"R7v-vK-OW3\">\n            <objects>\n                <viewController storyboardIdentifier=\"ImageWidgetViewController\" id=\"AEm-j3-7wr\" customClass=\"ImageWidgetViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"79A-lA-yaO\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"LIa-Qa-jfC\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"0Aa-Jf-Byp\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" distribution=\"fillEqually\" spacing=\"10\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oQU-3P-kV9\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"59\" width=\"393\" height=\"759\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"EYG-ca-juQ\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"246.33333333333334\"/>\n                                        <subviews>\n                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"dog4\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"zwM-oi-nK8\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"361\" height=\"246.33333333333334\"/>\n                                                <userDefinedRuntimeAttributes>\n                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                        <integer key=\"value\" value=\"4\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                </userDefinedRuntimeAttributes>\n                                            </imageView>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bt6-2W-TiT\">\n                                                <rect key=\"frame\" x=\"24\" y=\"206.33333333333331\" width=\"48\" height=\"32\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Local\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Mcg-yM-fTB\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"48\" height=\"32\"/>\n                                                        <color key=\"backgroundColor\" name=\"surface\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"12\"/>\n                                                        <color key=\"textColor\" name=\"text_not_selected\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" name=\"surface\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"Mcg-yM-fTB\" firstAttribute=\"leading\" secondItem=\"bt6-2W-TiT\" secondAttribute=\"leading\" id=\"BDE-G4-kFJ\"/>\n                                                    <constraint firstAttribute=\"width\" secondItem=\"bt6-2W-TiT\" secondAttribute=\"height\" multiplier=\"3:2\" id=\"OiV-Wx-FiY\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"Mcg-yM-fTB\" secondAttribute=\"trailing\" id=\"Xxa-Pe-Qhf\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"Mcg-yM-fTB\" secondAttribute=\"bottom\" id=\"lBI-uc-kxc\"/>\n                                                    <constraint firstItem=\"Mcg-yM-fTB\" firstAttribute=\"top\" secondItem=\"bt6-2W-TiT\" secondAttribute=\"top\" id=\"pbR-VO-Rhm\"/>\n                                                </constraints>\n                                                <userDefinedRuntimeAttributes>\n                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                        <integer key=\"value\" value=\"4\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                </userDefinedRuntimeAttributes>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"bt6-2W-TiT\" firstAttribute=\"width\" secondItem=\"zwM-oi-nK8\" secondAttribute=\"width\" multiplier=\"0.132964\" id=\"2cn-ba-lXE\"/>\n                                            <constraint firstItem=\"zwM-oi-nK8\" firstAttribute=\"leading\" secondItem=\"EYG-ca-juQ\" secondAttribute=\"leading\" constant=\"16\" id=\"Hhf-bV-jSj\"/>\n                                            <constraint firstItem=\"bt6-2W-TiT\" firstAttribute=\"bottom\" secondItem=\"zwM-oi-nK8\" secondAttribute=\"bottom\" constant=\"-8\" id=\"YGd-wG-TjT\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"zwM-oi-nK8\" secondAttribute=\"bottom\" id=\"Ztn-hu-LnU\"/>\n                                            <constraint firstItem=\"bt6-2W-TiT\" firstAttribute=\"leading\" secondItem=\"zwM-oi-nK8\" secondAttribute=\"leading\" constant=\"8\" id=\"af4-re-qDr\"/>\n                                            <constraint firstItem=\"zwM-oi-nK8\" firstAttribute=\"top\" secondItem=\"EYG-ca-juQ\" secondAttribute=\"top\" id=\"i7x-PO-Fpb\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"zwM-oi-nK8\" secondAttribute=\"trailing\" constant=\"16\" id=\"y3D-4O-blK\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7x6-Ay-VEh\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"256.33333333333331\" width=\"393\" height=\"246.33333333333331\"/>\n                                        <subviews>\n                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"dog4\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FSq-od-j4u\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"361\" height=\"246.33333333333334\"/>\n                                                <userDefinedRuntimeAttributes>\n                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                        <integer key=\"value\" value=\"4\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                </userDefinedRuntimeAttributes>\n                                            </imageView>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"m1K-AN-pdJ\">\n                                                <rect key=\"frame\" x=\"24\" y=\"206.33333333333331\" width=\"61\" height=\"32\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Remote\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"d6u-8C-xA9\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"61\" height=\"32\"/>\n                                                        <color key=\"backgroundColor\" name=\"surface\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"12\"/>\n                                                        <color key=\"textColor\" name=\"text_not_selected\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" name=\"surface\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"d6u-8C-xA9\" secondAttribute=\"trailing\" id=\"DlF-4Z-RHy\"/>\n                                                    <constraint firstAttribute=\"width\" secondItem=\"m1K-AN-pdJ\" secondAttribute=\"height\" multiplier=\"61:32\" id=\"ZY6-NC-Ioh\"/>\n                                                    <constraint firstItem=\"d6u-8C-xA9\" firstAttribute=\"top\" secondItem=\"m1K-AN-pdJ\" secondAttribute=\"top\" id=\"gbs-36-UIp\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"d6u-8C-xA9\" secondAttribute=\"bottom\" id=\"xmh-Ht-GmE\"/>\n                                                    <constraint firstItem=\"d6u-8C-xA9\" firstAttribute=\"leading\" secondItem=\"m1K-AN-pdJ\" secondAttribute=\"leading\" id=\"z3m-rt-ILr\"/>\n                                                </constraints>\n                                                <userDefinedRuntimeAttributes>\n                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                        <integer key=\"value\" value=\"4\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                </userDefinedRuntimeAttributes>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"FSq-od-j4u\" firstAttribute=\"leading\" secondItem=\"7x6-Ay-VEh\" secondAttribute=\"leading\" constant=\"16\" id=\"1KH-EF-Ac6\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"FSq-od-j4u\" secondAttribute=\"bottom\" id=\"1bJ-4E-9zo\"/>\n                                            <constraint firstItem=\"m1K-AN-pdJ\" firstAttribute=\"width\" secondItem=\"FSq-od-j4u\" secondAttribute=\"width\" multiplier=\"0.168975\" id=\"HQH-TM-0a4\"/>\n                                            <constraint firstItem=\"m1K-AN-pdJ\" firstAttribute=\"leading\" secondItem=\"FSq-od-j4u\" secondAttribute=\"leading\" constant=\"8\" id=\"ZYT-0J-UoI\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"FSq-od-j4u\" secondAttribute=\"trailing\" constant=\"16\" id=\"b3Z-ob-tfg\"/>\n                                            <constraint firstItem=\"FSq-od-j4u\" firstAttribute=\"top\" secondItem=\"7x6-Ay-VEh\" secondAttribute=\"top\" id=\"nWH-Au-p5e\"/>\n                                            <constraint firstItem=\"m1K-AN-pdJ\" firstAttribute=\"bottom\" secondItem=\"FSq-od-j4u\" secondAttribute=\"bottom\" constant=\"-8\" id=\"o3V-rB-mMx\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ott-KW-FFc\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"512.66666666666663\" width=\"393\" height=\"246.33333333333337\"/>\n                                        <subviews>\n                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"dog4\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VY3-vy-C7I\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"361\" height=\"246.33333333333334\"/>\n                                                <userDefinedRuntimeAttributes>\n                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                        <integer key=\"value\" value=\"4\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                </userDefinedRuntimeAttributes>\n                                            </imageView>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"cmM-pG-LK6\">\n                                                <rect key=\"frame\" x=\"24\" y=\"206.33333333333337\" width=\"80\" height=\"32\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Cloudinary\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qsV-ac-rL8\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"80\" height=\"32\"/>\n                                                        <color key=\"backgroundColor\" name=\"surface\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"12\"/>\n                                                        <color key=\"textColor\" name=\"text_not_selected\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" name=\"surface\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"qsV-ac-rL8\" secondAttribute=\"trailing\" id=\"38g-HW-DJt\"/>\n                                                    <constraint firstAttribute=\"width\" secondItem=\"cmM-pG-LK6\" secondAttribute=\"height\" multiplier=\"5:2\" id=\"3Hc-hs-tbh\"/>\n                                                    <constraint firstItem=\"qsV-ac-rL8\" firstAttribute=\"leading\" secondItem=\"cmM-pG-LK6\" secondAttribute=\"leading\" id=\"FmN-3W-yY6\"/>\n                                                    <constraint firstItem=\"qsV-ac-rL8\" firstAttribute=\"top\" secondItem=\"cmM-pG-LK6\" secondAttribute=\"top\" id=\"Sxs-yX-DBN\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"qsV-ac-rL8\" secondAttribute=\"bottom\" id=\"gw4-r6-MnZ\"/>\n                                                </constraints>\n                                                <userDefinedRuntimeAttributes>\n                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                        <integer key=\"value\" value=\"4\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                </userDefinedRuntimeAttributes>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"VY3-vy-C7I\" secondAttribute=\"trailing\" constant=\"16\" id=\"6q0-Q0-v8g\"/>\n                                            <constraint firstItem=\"VY3-vy-C7I\" firstAttribute=\"top\" secondItem=\"ott-KW-FFc\" secondAttribute=\"top\" id=\"Daq-W9-Plg\"/>\n                                            <constraint firstItem=\"cmM-pG-LK6\" firstAttribute=\"width\" secondItem=\"VY3-vy-C7I\" secondAttribute=\"width\" multiplier=\"0.221607\" id=\"Yn9-29-hO1\"/>\n                                            <constraint firstItem=\"cmM-pG-LK6\" firstAttribute=\"leading\" secondItem=\"VY3-vy-C7I\" secondAttribute=\"leading\" constant=\"8\" id=\"kST-m6-Kxn\"/>\n                                            <constraint firstItem=\"cmM-pG-LK6\" firstAttribute=\"bottom\" secondItem=\"VY3-vy-C7I\" secondAttribute=\"bottom\" constant=\"-8\" id=\"obX-oL-71p\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"VY3-vy-C7I\" secondAttribute=\"bottom\" id=\"uds-tJ-KO9\"/>\n                                            <constraint firstItem=\"VY3-vy-C7I\" firstAttribute=\"leading\" secondItem=\"ott-KW-FFc\" secondAttribute=\"leading\" constant=\"16\" id=\"wCb-Qu-c8F\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                            </stackView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"hDg-5e-xSP\"/>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"oQU-3P-kV9\" firstAttribute=\"leading\" secondItem=\"hDg-5e-xSP\" secondAttribute=\"leading\" id=\"1q5-VW-0pp\"/>\n                            <constraint firstItem=\"oQU-3P-kV9\" firstAttribute=\"top\" secondItem=\"hDg-5e-xSP\" secondAttribute=\"top\" id=\"IKF-l5-JYl\"/>\n                            <constraint firstItem=\"hDg-5e-xSP\" firstAttribute=\"bottom\" secondItem=\"oQU-3P-kV9\" secondAttribute=\"bottom\" id=\"W0n-M6-Srh\"/>\n                            <constraint firstItem=\"hDg-5e-xSP\" firstAttribute=\"trailing\" secondItem=\"oQU-3P-kV9\" secondAttribute=\"trailing\" id=\"XeU-G7-ibq\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"852\"/>\n                    <connections>\n                        <outlet property=\"ivCloudinary\" destination=\"VY3-vy-C7I\" id=\"VMk-xw-Owp\"/>\n                        <outlet property=\"ivLocal\" destination=\"zwM-oi-nK8\" id=\"V5w-HL-bXd\"/>\n                        <outlet property=\"ivRemote\" destination=\"FSq-od-j4u\" id=\"dhT-aE-4wM\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"cba-i9-5sY\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-807\" y=\"-150\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"dog4\" width=\"959\" height=\"540\"/>\n        <namedColor name=\"surface\">\n            <color red=\"0.12549019607843137\" green=\"0.14117647058823529\" blue=\"0.17647058823529413\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"text_not_selected\">\n            <color red=\"1\" green=\"1\" blue=\"0.99607843137254903\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Widgets/UploadWidget.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Stack View standard spacing\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Upload Widget View Controller-->\n        <scene sceneID=\"rda-Yv-EU3\">\n            <objects>\n                <viewController storyboardIdentifier=\"UploadWidgetViewController\" id=\"bpT-QB-1op\" customClass=\"UploadWidgetViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"PUL-kf-bX9\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"VMV-Yd-NwN\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5UE-sn-Vn3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacingType=\"standard\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Pim-Ws-exg\">\n                                <rect key=\"frame\" x=\"16\" y=\"59\" width=\"361\" height=\"759\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mDl-BS-0UY\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"599.33333333333337\"/>\n                                        <subviews>\n                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"rim-zF-149\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"599.33333333333337\"/>\n                                            </imageView>\n                                            <activityIndicatorView hidden=\"YES\" opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" fixedFrame=\"YES\" animating=\"YES\" style=\"large\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aUs-FJ-hUP\">\n                                                <rect key=\"frame\" x=\"162\" y=\"300\" width=\"37\" height=\"37\"/>\n                                                <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                <color key=\"color\" name=\"primary\"/>\n                                            </activityIndicatorView>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eSR-Vb-x2p\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"599.33333333333337\"/>\n                                                <subviews>\n                                                    <view alpha=\"0.20000000298023224\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"vXW-Oi-IXK\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"599.33333333333337\"/>\n                                                        <color key=\"backgroundColor\" name=\"primary\"/>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Giq-ps-ZJx\">\n                                                        <rect key=\"frame\" x=\"68\" y=\"189\" width=\"225\" height=\"221\"/>\n                                                        <subviews>\n                                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"lfT-4t-eDk\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"225\" height=\"221\"/>\n                                                                <subviews>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Wdu-bk-BET\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"225\" height=\"106.33333333333333\"/>\n                                                                        <subviews>\n                                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"upload_missing\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"N6p-Rn-DRA\">\n                                                                                <rect key=\"frame\" x=\"48.333333333333343\" y=\"-11\" width=\"128.33333333333334\" height=\"128.33333333333334\"/>\n                                                                                <constraints>\n                                                                                    <constraint firstAttribute=\"width\" secondItem=\"N6p-Rn-DRA\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"mMD-GK-tx1\"/>\n                                                                                </constraints>\n                                                                            </imageView>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstItem=\"N6p-Rn-DRA\" firstAttribute=\"height\" secondItem=\"Wdu-bk-BET\" secondAttribute=\"height\" multiplier=\"1.20755\" id=\"3Y5-4E-o1a\"/>\n                                                                            <constraint firstItem=\"N6p-Rn-DRA\" firstAttribute=\"centerY\" secondItem=\"Wdu-bk-BET\" secondAttribute=\"centerY\" id=\"mH0-5z-QyE\"/>\n                                                                            <constraint firstItem=\"N6p-Rn-DRA\" firstAttribute=\"centerX\" secondItem=\"Wdu-bk-BET\" secondAttribute=\"centerX\" id=\"od4-i3-QS4\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VeV-r2-jgh\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"106.33333333333333\" width=\"225\" height=\"50.666666666666671\"/>\n                                                                        <subviews>\n                                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Upload your image now and let the magic begin!\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hkz-QP-cft\">\n                                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"225\" height=\"50.666666666666664\"/>\n                                                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"16\"/>\n                                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                                <nil key=\"highlightedColor\"/>\n                                                                            </label>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"hkz-QP-cft\" secondAttribute=\"bottom\" id=\"7D4-Ad-Gpx\"/>\n                                                                            <constraint firstItem=\"hkz-QP-cft\" firstAttribute=\"leading\" secondItem=\"VeV-r2-jgh\" secondAttribute=\"leading\" id=\"XKN-mD-6Ut\"/>\n                                                                            <constraint firstItem=\"hkz-QP-cft\" firstAttribute=\"top\" secondItem=\"VeV-r2-jgh\" secondAttribute=\"top\" id=\"ul7-ap-dQQ\"/>\n                                                                            <constraint firstAttribute=\"trailing\" secondItem=\"hkz-QP-cft\" secondAttribute=\"trailing\" id=\"vK4-t6-5IO\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qz8-o6-T4b\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"157\" width=\"225\" height=\"64\"/>\n                                                                        <subviews>\n                                                                            <view hidden=\"YES\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eqQ-Zl-o40\">\n                                                                                <rect key=\"frame\" x=\"39.333333333333329\" y=\"21.333333333333311\" width=\"146.33333333333337\" height=\"42.666666666666657\"/>\n                                                                                <subviews>\n                                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Upload Image\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"isb-7b-PU2\">\n                                                                                        <rect key=\"frame\" x=\"20.333333333333321\" y=\"10.999999999999998\" width=\"105.66666666666669\" height=\"20.333333333333329\"/>\n                                                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                                                        <nil key=\"textColor\"/>\n                                                                                        <nil key=\"highlightedColor\"/>\n                                                                                    </label>\n                                                                                </subviews>\n                                                                                <color key=\"backgroundColor\" name=\"primary\"/>\n                                                                                <constraints>\n                                                                                    <constraint firstItem=\"isb-7b-PU2\" firstAttribute=\"centerX\" secondItem=\"eqQ-Zl-o40\" secondAttribute=\"centerX\" id=\"Q06-DZ-3hG\"/>\n                                                                                    <constraint firstAttribute=\"width\" secondItem=\"eqQ-Zl-o40\" secondAttribute=\"height\" multiplier=\"75:22\" id=\"dJK-xu-5xI\"/>\n                                                                                    <constraint firstItem=\"isb-7b-PU2\" firstAttribute=\"centerY\" secondItem=\"eqQ-Zl-o40\" secondAttribute=\"centerY\" id=\"keB-4r-HX7\"/>\n                                                                                </constraints>\n                                                                            </view>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstItem=\"eqQ-Zl-o40\" firstAttribute=\"width\" secondItem=\"qz8-o6-T4b\" secondAttribute=\"width\" multiplier=\"0.65\" id=\"4bd-dv-jUw\"/>\n                                                                            <constraint firstItem=\"eqQ-Zl-o40\" firstAttribute=\"centerX\" secondItem=\"qz8-o6-T4b\" secondAttribute=\"centerX\" id=\"XZq-8f-vht\"/>\n                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"eqQ-Zl-o40\" secondAttribute=\"bottom\" id=\"j0K-6K-fWi\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                </subviews>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"Wdu-bk-BET\" firstAttribute=\"height\" secondItem=\"lfT-4t-eDk\" secondAttribute=\"height\" multiplier=\"0.48\" id=\"PJF-Pc-kME\"/>\n                                                                    <constraint firstItem=\"VeV-r2-jgh\" firstAttribute=\"height\" secondItem=\"lfT-4t-eDk\" secondAttribute=\"height\" multiplier=\"0.23\" id=\"Y4L-22-ngN\"/>\n                                                                </constraints>\n                                                            </stackView>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"lfT-4t-eDk\" firstAttribute=\"top\" secondItem=\"Giq-ps-ZJx\" secondAttribute=\"top\" id=\"2fX-aG-Nnt\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"lfT-4t-eDk\" secondAttribute=\"bottom\" id=\"3Sm-7S-vOp\"/>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"lfT-4t-eDk\" secondAttribute=\"trailing\" id=\"Ajt-nd-rsU\"/>\n                                                            <constraint firstAttribute=\"width\" secondItem=\"Giq-ps-ZJx\" secondAttribute=\"height\" multiplier=\"225:221\" id=\"Bzc-wB-8AF\"/>\n                                                            <constraint firstItem=\"lfT-4t-eDk\" firstAttribute=\"leading\" secondItem=\"Giq-ps-ZJx\" secondAttribute=\"leading\" id=\"ZLT-lc-iBg\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Please add the upload preset “ios_sample” to your account for successful upload\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Dve-5K-5rz\">\n                                                        <rect key=\"frame\" x=\"16\" y=\"549.66666666666663\" width=\"329\" height=\"33.666666666666629\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"vXW-Oi-IXK\" firstAttribute=\"top\" secondItem=\"eSR-Vb-x2p\" secondAttribute=\"top\" id=\"1CB-Mw-uau\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"vXW-Oi-IXK\" secondAttribute=\"bottom\" id=\"3Gm-HH-8xQ\"/>\n                                                    <constraint firstItem=\"Giq-ps-ZJx\" firstAttribute=\"centerX\" secondItem=\"eSR-Vb-x2p\" secondAttribute=\"centerX\" id=\"C65-OY-aMQ\"/>\n                                                    <constraint firstItem=\"Giq-ps-ZJx\" firstAttribute=\"width\" secondItem=\"eSR-Vb-x2p\" secondAttribute=\"width\" multiplier=\"0.623269\" id=\"Eyt-pz-9Ys\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"Dve-5K-5rz\" secondAttribute=\"trailing\" constant=\"16\" id=\"IEm-gI-6E1\"/>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"Dve-5K-5rz\" secondAttribute=\"bottom\" constant=\"16\" id=\"OGH-Hf-T0p\"/>\n                                                    <constraint firstItem=\"Dve-5K-5rz\" firstAttribute=\"leading\" secondItem=\"eSR-Vb-x2p\" secondAttribute=\"leading\" constant=\"16\" id=\"Pdn-YN-zed\"/>\n                                                    <constraint firstItem=\"vXW-Oi-IXK\" firstAttribute=\"leading\" secondItem=\"eSR-Vb-x2p\" secondAttribute=\"leading\" id=\"UIn-i4-udX\"/>\n                                                    <constraint firstItem=\"Giq-ps-ZJx\" firstAttribute=\"centerY\" secondItem=\"eSR-Vb-x2p\" secondAttribute=\"centerY\" id=\"utd-Uu-poc\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"vXW-Oi-IXK\" secondAttribute=\"trailing\" id=\"y23-py-cjE\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"eSR-Vb-x2p\" secondAttribute=\"trailing\" id=\"4E3-4k-bdm\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"rim-zF-149\" secondAttribute=\"bottom\" id=\"6bf-zb-MlO\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"eSR-Vb-x2p\" secondAttribute=\"bottom\" id=\"Uos-Px-frl\"/>\n                                            <constraint firstItem=\"rim-zF-149\" firstAttribute=\"top\" secondItem=\"mDl-BS-0UY\" secondAttribute=\"top\" id=\"V10-GK-3TA\"/>\n                                            <constraint firstItem=\"eSR-Vb-x2p\" firstAttribute=\"leading\" secondItem=\"mDl-BS-0UY\" secondAttribute=\"leading\" id=\"YBa-qj-u4B\"/>\n                                            <constraint firstItem=\"rim-zF-149\" firstAttribute=\"leading\" secondItem=\"mDl-BS-0UY\" secondAttribute=\"leading\" id=\"anM-TG-hDS\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"rim-zF-149\" secondAttribute=\"trailing\" id=\"v7v-ky-V38\"/>\n                                            <constraint firstItem=\"eSR-Vb-x2p\" firstAttribute=\"top\" secondItem=\"mDl-BS-0UY\" secondAttribute=\"top\" id=\"yVO-eF-RhN\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Jf6-K6-Acc\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"607.33333333333337\" width=\"361\" height=\"151.66666666666663\"/>\n                                        <subviews>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"u3l-6r-6vY\">\n                                                <rect key=\"frame\" x=\"16.666666666666657\" y=\"55.666666666666629\" width=\"328\" height=\"40\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Open Upload Widget\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ae2-KJ-r9i\">\n                                                        <rect key=\"frame\" x=\"94.999999999999986\" y=\"11.666666666666629\" width=\"137.66666666666663\" height=\"17\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"14\"/>\n                                                        <nil key=\"textColor\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" name=\"primary\"/>\n                                                <constraints>\n                                                    <constraint firstItem=\"Ae2-KJ-r9i\" firstAttribute=\"centerY\" secondItem=\"u3l-6r-6vY\" secondAttribute=\"centerY\" id=\"CPd-Uf-n09\"/>\n                                                    <constraint firstAttribute=\"width\" secondItem=\"u3l-6r-6vY\" secondAttribute=\"height\" multiplier=\"41:5\" id=\"LR9-Id-JNn\"/>\n                                                    <constraint firstItem=\"Ae2-KJ-r9i\" firstAttribute=\"centerX\" secondItem=\"u3l-6r-6vY\" secondAttribute=\"centerX\" id=\"mif-M9-4MO\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"u3l-6r-6vY\" firstAttribute=\"centerY\" secondItem=\"Jf6-K6-Acc\" secondAttribute=\"centerY\" id=\"8Oi-sq-ApC\"/>\n                                            <constraint firstItem=\"u3l-6r-6vY\" firstAttribute=\"centerX\" secondItem=\"Jf6-K6-Acc\" secondAttribute=\"centerX\" id=\"uER-FT-kOo\"/>\n                                            <constraint firstItem=\"u3l-6r-6vY\" firstAttribute=\"width\" secondItem=\"Jf6-K6-Acc\" secondAttribute=\"width\" multiplier=\"0.908587\" id=\"yUA-Yc-jPw\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"Jf6-K6-Acc\" firstAttribute=\"height\" secondItem=\"Pim-Ws-exg\" secondAttribute=\"height\" multiplier=\"0.2\" id=\"ZzU-AI-hux\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"SlD-Gc-4yt\"/>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"Pim-Ws-exg\" firstAttribute=\"leading\" secondItem=\"5UE-sn-Vn3\" secondAttribute=\"leadingMargin\" id=\"cgz-cH-A3P\"/>\n                            <constraint firstItem=\"Pim-Ws-exg\" firstAttribute=\"top\" secondItem=\"PUL-kf-bX9\" secondAttribute=\"bottom\" id=\"uIU-a9-fOu\"/>\n                            <constraint firstAttribute=\"trailingMargin\" secondItem=\"Pim-Ws-exg\" secondAttribute=\"trailing\" id=\"uw9-P1-AFn\"/>\n                            <constraint firstItem=\"VMV-Yd-NwN\" firstAttribute=\"top\" secondItem=\"Pim-Ws-exg\" secondAttribute=\"bottom\" id=\"yI8-lH-dxq\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"852\"/>\n                    <connections>\n                        <outlet property=\"aiLoading\" destination=\"aUs-FJ-hUP\" id=\"DIg-Iy-r8E\"/>\n                        <outlet property=\"ivMain\" destination=\"rim-zF-149\" id=\"7Gl-Rn-rcg\"/>\n                        <outlet property=\"vwOpenGallery\" destination=\"u3l-6r-6vY\" id=\"5Gg-MF-iMa\"/>\n                        <outlet property=\"vwUploadContainer\" destination=\"eSR-Vb-x2p\" id=\"oiA-tb-BN4\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"JyK-VH-56j\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-807\" y=\"-150\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"upload_missing\" width=\"125\" height=\"107\"/>\n        <namedColor name=\"primary\">\n            <color red=\"0.27450980392156865\" green=\"0.59607843137254901\" blue=\"0.96862745098039216\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Inner Views/Widgets/Widgets.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Widgets View Controller-->\n        <scene sceneID=\"s0d-6b-0kx\">\n            <objects>\n                <viewController storyboardIdentifier=\"WidgetsViewController\" id=\"Y6W-OH-hqX\" customClass=\"WidgetsViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5EZ-qb-Rvc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PYG-Ld-MWV\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"59\" width=\"393\" height=\"759\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5xt-dc-MPO\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"102.33333333333333\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FOW-Iu-sMX\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"102.33333333333333\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KiT-GP-el8\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"66.666666666666671\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Widgets\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yUw-1f-aqL\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"11.666666666666671\" width=\"136.33333333333334\" height=\"43\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"semibold\" pointSize=\"36\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"yUw-1f-aqL\" firstAttribute=\"leading\" secondItem=\"KiT-GP-el8\" secondAttribute=\"leading\" constant=\"16\" id=\"Oln-lS-vVu\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"yUw-1f-aqL\" secondAttribute=\"bottom\" constant=\"12\" id=\"Z5n-fv-Caz\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"s5S-SI-JFZ\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"66.666666666666671\" width=\"393\" height=\"35.666666666666671\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"95w-sv-167\">\n                                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"47\" height=\"5\"/>\n                                                                <color key=\"backgroundColor\" name=\"primary\"/>\n                                                                <constraints>\n                                                                    <constraint firstAttribute=\"height\" constant=\"5\" id=\"kEx-fw-Pyz\"/>\n                                                                </constraints>\n                                                                <userDefinedRuntimeAttributes>\n                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                        <real key=\"value\" value=\"2.5\"/>\n                                                                    </userDefinedRuntimeAttribute>\n                                                                </userDefinedRuntimeAttributes>\n                                                            </view>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"95w-sv-167\" firstAttribute=\"top\" secondItem=\"s5S-SI-JFZ\" secondAttribute=\"top\" id=\"DAk-C6-Lap\"/>\n                                                            <constraint firstItem=\"95w-sv-167\" firstAttribute=\"leading\" secondItem=\"s5S-SI-JFZ\" secondAttribute=\"leading\" constant=\"16\" id=\"fjx-9X-9bt\"/>\n                                                            <constraint firstItem=\"95w-sv-167\" firstAttribute=\"width\" secondItem=\"s5S-SI-JFZ\" secondAttribute=\"width\" multiplier=\"0.119593\" id=\"n0R-gS-PCi\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"KiT-GP-el8\" firstAttribute=\"height\" secondItem=\"FOW-Iu-sMX\" secondAttribute=\"height\" multiplier=\"0.65\" id=\"LLf-nX-K8Q\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"FOW-Iu-sMX\" secondAttribute=\"trailing\" id=\"ALm-Cx-Vxk\"/>\n                                            <constraint firstItem=\"FOW-Iu-sMX\" firstAttribute=\"leading\" secondItem=\"5xt-dc-MPO\" secondAttribute=\"leading\" id=\"Bd7-am-x5I\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"FOW-Iu-sMX\" secondAttribute=\"bottom\" id=\"MZF-sl-UBU\"/>\n                                            <constraint firstItem=\"FOW-Iu-sMX\" firstAttribute=\"top\" secondItem=\"5xt-dc-MPO\" secondAttribute=\"top\" id=\"tft-gm-x5y\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"6HE-Wd-Jya\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"102.33333333333334\" width=\"393\" height=\"311.33333333333326\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dhF-uS-ocg\">\n                                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"361\" height=\"311.33333333333331\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aA1-fu-iT1\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"31\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Upload Widget\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"f4G-Nw-ZXk\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"122.66666666666667\" height=\"21.666666666666668\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"f4G-Nw-ZXk\" firstAttribute=\"leading\" secondItem=\"aA1-fu-iT1\" secondAttribute=\"leading\" id=\"45t-1Q-Eb1\"/>\n                                                            <constraint firstItem=\"f4G-Nw-ZXk\" firstAttribute=\"top\" secondItem=\"aA1-fu-iT1\" secondAttribute=\"top\" id=\"eML-H6-8Xa\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Bxa-Ra-Qq3\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"31\" width=\"361\" height=\"26.666666666666671\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Streamline your media uploads seamlessly\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mV9-2h-Ii7\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"3.6666666666666572\" width=\"307.33333333333331\" height=\"19.333333333333332\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"16\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"mV9-2h-Ii7\" firstAttribute=\"leading\" secondItem=\"Bxa-Ra-Qq3\" secondAttribute=\"leading\" id=\"9EJ-sG-ERd\"/>\n                                                            <constraint firstItem=\"mV9-2h-Ii7\" firstAttribute=\"centerY\" secondItem=\"Bxa-Ra-Qq3\" secondAttribute=\"centerY\" id=\"hOc-q9-pn3\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"G09-sS-Kd9\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"57.666666666666671\" width=\"361\" height=\"253.66666666666663\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"mIa-dZ-5Ky\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"8\" width=\"361\" height=\"215.66666666666666\"/>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                            </view>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"mIa-dZ-5Ky\" firstAttribute=\"leading\" secondItem=\"G09-sS-Kd9\" secondAttribute=\"leading\" id=\"kyi-6U-vpE\"/>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"mIa-dZ-5Ky\" secondAttribute=\"trailing\" id=\"tlL-hp-ocC\"/>\n                                                            <constraint firstItem=\"mIa-dZ-5Ky\" firstAttribute=\"top\" secondItem=\"G09-sS-Kd9\" secondAttribute=\"top\" constant=\"8\" id=\"ugf-4T-uOw\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"mIa-dZ-5Ky\" secondAttribute=\"bottom\" constant=\"30\" id=\"vm9-YS-xUp\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"Bxa-Ra-Qq3\" firstAttribute=\"height\" secondItem=\"dhF-uS-ocg\" secondAttribute=\"height\" multiplier=\"0.085\" id=\"FWg-FL-fG7\"/>\n                                                    <constraint firstItem=\"aA1-fu-iT1\" firstAttribute=\"height\" secondItem=\"dhF-uS-ocg\" secondAttribute=\"height\" multiplier=\"0.1\" id=\"g3r-nj-rfs\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"dhF-uS-ocg\" firstAttribute=\"top\" secondItem=\"6HE-Wd-Jya\" secondAttribute=\"top\" id=\"EkL-2K-uxV\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"dhF-uS-ocg\" secondAttribute=\"bottom\" id=\"KxH-HS-3GT\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"dhF-uS-ocg\" secondAttribute=\"trailing\" constant=\"16\" id=\"M2E-V3-gAC\"/>\n                                            <constraint firstItem=\"dhF-uS-ocg\" firstAttribute=\"leading\" secondItem=\"6HE-Wd-Jya\" secondAttribute=\"leading\" constant=\"16\" id=\"YEb-3e-N34\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"2dg-7g-lUB\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"413.66666666666674\" width=\"393\" height=\"345.33333333333326\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"gu8-wJ-yYY\">\n                                                <rect key=\"frame\" x=\"16\" y=\"8\" width=\"361\" height=\"337.33333333333331\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"otY-Uq-fzE\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"33.666666666666664\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Image Widget\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eLA-Uo-wPq\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"114.66666666666667\" height=\"21.666666666666668\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"18\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"eLA-Uo-wPq\" firstAttribute=\"top\" secondItem=\"otY-Uq-fzE\" secondAttribute=\"top\" id=\"0fB-70-20r\"/>\n                                                            <constraint firstItem=\"eLA-Uo-wPq\" firstAttribute=\"leading\" secondItem=\"otY-Uq-fzE\" secondAttribute=\"leading\" id=\"vWm-X0-Gbv\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"dbG-mq-FdN\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"33.666666666666686\" width=\"361\" height=\"57.333333333333343\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Add images effortlessly from your device, external sources, or Cloudinary assets to enhance your project.\" textAlignment=\"natural\" lineBreakMode=\"wordWrap\" numberOfLines=\"3\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"nR8-RR-h4a\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"345\" height=\"57.333333333333336\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"16\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"nR8-RR-h4a\" firstAttribute=\"centerY\" secondItem=\"dbG-mq-FdN\" secondAttribute=\"centerY\" id=\"7BR-oo-GlV\"/>\n                                                            <constraint firstItem=\"nR8-RR-h4a\" firstAttribute=\"leading\" secondItem=\"dbG-mq-FdN\" secondAttribute=\"leading\" id=\"LrO-Va-7Sy\"/>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"nR8-RR-h4a\" secondAttribute=\"trailing\" constant=\"16\" id=\"tRr-Ii-mK2\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uhz-OY-VWC\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"90.999999999999957\" width=\"361\" height=\"246.33333333333337\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FKM-Uc-P5d\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"8\" width=\"361\" height=\"208.33333333333334\"/>\n                                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                            </view>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"FKM-Uc-P5d\" firstAttribute=\"top\" secondItem=\"uhz-OY-VWC\" secondAttribute=\"top\" constant=\"8\" id=\"3B5-En-eIn\"/>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"FKM-Uc-P5d\" secondAttribute=\"trailing\" id=\"HEo-eX-dav\"/>\n                                                            <constraint firstItem=\"FKM-Uc-P5d\" firstAttribute=\"leading\" secondItem=\"uhz-OY-VWC\" secondAttribute=\"leading\" id=\"nIx-UR-2tq\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"FKM-Uc-P5d\" secondAttribute=\"bottom\" constant=\"30\" id=\"vTD-pd-Mau\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"dbG-mq-FdN\" firstAttribute=\"height\" secondItem=\"gu8-wJ-yYY\" secondAttribute=\"height\" multiplier=\"0.17\" id=\"66l-A0-v4n\"/>\n                                                    <constraint firstItem=\"otY-Uq-fzE\" firstAttribute=\"height\" secondItem=\"gu8-wJ-yYY\" secondAttribute=\"height\" multiplier=\"0.1\" id=\"uhc-L2-2ru\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"gu8-wJ-yYY\" secondAttribute=\"trailing\" constant=\"16\" id=\"2HK-lK-zZk\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"gu8-wJ-yYY\" secondAttribute=\"bottom\" id=\"Nsd-Hy-xCX\"/>\n                                            <constraint firstItem=\"gu8-wJ-yYY\" firstAttribute=\"leading\" secondItem=\"2dg-7g-lUB\" secondAttribute=\"leading\" constant=\"16\" id=\"jHZ-Dx-Pki\"/>\n                                            <constraint firstItem=\"gu8-wJ-yYY\" firstAttribute=\"top\" secondItem=\"2dg-7g-lUB\" secondAttribute=\"top\" constant=\"8\" id=\"zTw-U5-0bX\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"6HE-Wd-Jya\" firstAttribute=\"height\" secondItem=\"PYG-Ld-MWV\" secondAttribute=\"height\" multiplier=\"0.41\" id=\"0wg-UL-bQq\"/>\n                                    <constraint firstItem=\"5xt-dc-MPO\" firstAttribute=\"height\" secondItem=\"PYG-Ld-MWV\" secondAttribute=\"height\" multiplier=\"0.134827\" id=\"cbM-k2-zfj\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"vDu-zF-Fre\"/>\n                        <color key=\"backgroundColor\" name=\"surface\"/>\n                        <constraints>\n                            <constraint firstItem=\"PYG-Ld-MWV\" firstAttribute=\"bottom\" secondItem=\"vDu-zF-Fre\" secondAttribute=\"bottom\" id=\"0lV-zq-YHX\"/>\n                            <constraint firstItem=\"PYG-Ld-MWV\" firstAttribute=\"leading\" secondItem=\"vDu-zF-Fre\" secondAttribute=\"leading\" id=\"ZlV-kb-H3o\"/>\n                            <constraint firstItem=\"vDu-zF-Fre\" firstAttribute=\"trailing\" secondItem=\"PYG-Ld-MWV\" secondAttribute=\"trailing\" id=\"gMu-tU-D2A\"/>\n                            <constraint firstItem=\"vDu-zF-Fre\" firstAttribute=\"top\" secondItem=\"PYG-Ld-MWV\" secondAttribute=\"top\" id=\"i6E-To-Imf\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"vwImageWidget\" destination=\"2dg-7g-lUB\" id=\"lq3-TD-lca\"/>\n                        <outlet property=\"vwImageWidgetVideo\" destination=\"FKM-Uc-P5d\" id=\"3dS-y3-td5\"/>\n                        <outlet property=\"vwUploadWidget\" destination=\"6HE-Wd-Jya\" id=\"qBW-JL-O9W\"/>\n                        <outlet property=\"vwUploadWidgetVideo\" destination=\"mIa-dZ-5Ky\" id=\"F4t-6u-Qh3\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Ief-a0-LHa\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"74\" y=\"4\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <namedColor name=\"primary\">\n            <color red=\"0.27450980392156865\" green=\"0.59607843137254901\" blue=\"0.96862745098039216\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n        <namedColor name=\"surface\">\n            <color red=\"0.12549019607843137\" green=\"0.14117647058823529\" blue=\"0.17647058823529413\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Splash.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"Y6W-OH-hqX\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"System colors in document resources\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Splash View Controller-->\n        <scene sceneID=\"s0d-6b-0kx\">\n            <objects>\n                <viewController id=\"Y6W-OH-hqX\" customClass=\"SplashViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5EZ-qb-Rvc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"splash\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"9em-iI-7TB\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                            </imageView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"vDu-zF-Fre\"/>\n                        <color key=\"backgroundColor\" systemColor=\"systemBackgroundColor\"/>\n                        <constraints>\n                            <constraint firstItem=\"9em-iI-7TB\" firstAttribute=\"leading\" secondItem=\"vDu-zF-Fre\" secondAttribute=\"leading\" id=\"O5m-xl-A3t\"/>\n                            <constraint firstItem=\"9em-iI-7TB\" firstAttribute=\"trailing\" secondItem=\"vDu-zF-Fre\" secondAttribute=\"trailing\" id=\"TJ8-L1-PA2\"/>\n                            <constraint firstItem=\"9em-iI-7TB\" firstAttribute=\"top\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"top\" id=\"ehV-t4-qsF\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"9em-iI-7TB\" secondAttribute=\"bottom\" id=\"jGl-bV-pWi\"/>\n                        </constraints>\n                        <userDefinedRuntimeAttributes>\n                            <userDefinedRuntimeAttribute type=\"color\" keyPath=\"firstColor\">\n                                <color key=\"value\" systemColor=\"systemMintColor\"/>\n                            </userDefinedRuntimeAttribute>\n                            <userDefinedRuntimeAttribute type=\"color\" keyPath=\"secondColor\">\n                                <color key=\"value\" systemColor=\"systemCyanColor\"/>\n                            </userDefinedRuntimeAttribute>\n                        </userDefinedRuntimeAttributes>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Ief-a0-LHa\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"74\" y=\"4\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"splash\" width=\"786\" height=\"1704\"/>\n        <systemColor name=\"systemBackgroundColor\">\n            <color white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n        </systemColor>\n        <systemColor name=\"systemCyanColor\">\n            <color red=\"0.19607843137254902\" green=\"0.67843137254901964\" blue=\"0.90196078431372551\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </systemColor>\n        <systemColor name=\"systemMintColor\">\n            <color red=\"0.0\" green=\"0.7803921568627451\" blue=\"0.74509803921568629\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </systemColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Transform/RevealImage.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Reveal Image Controller-->\n        <scene sceneID=\"nWM-t7-WIy\">\n            <objects>\n                <viewController storyboardIdentifier=\"RevealImageController\" id=\"y2e-Qv-th7\" customClass=\"RevealImageController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"CiV-XY-gil\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"BeY-rb-Q48\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"w6e-k7-za6\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"603\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"A8J-br-4wp\" customClass=\"RevealImageView\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                <rect key=\"frame\" x=\"16\" y=\"59\" width=\"361\" height=\"510\"/>\n                            </imageView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"ICF-DC-3m3\"/>\n                        <color key=\"backgroundColor\" name=\"surface\"/>\n                        <constraints>\n                            <constraint firstItem=\"ICF-DC-3m3\" firstAttribute=\"bottom\" secondItem=\"A8J-br-4wp\" secondAttribute=\"bottom\" id=\"Oav-t7-dU7\"/>\n                            <constraint firstItem=\"ICF-DC-3m3\" firstAttribute=\"trailing\" secondItem=\"A8J-br-4wp\" secondAttribute=\"trailing\" constant=\"16\" id=\"TBR-Ql-NKc\"/>\n                            <constraint firstItem=\"A8J-br-4wp\" firstAttribute=\"leading\" secondItem=\"ICF-DC-3m3\" secondAttribute=\"leading\" constant=\"16\" id=\"hWN-gu-iqj\"/>\n                            <constraint firstItem=\"A8J-br-4wp\" firstAttribute=\"top\" secondItem=\"ICF-DC-3m3\" secondAttribute=\"top\" id=\"nFV-cX-hfz\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"603\"/>\n                    <connections>\n                        <outlet property=\"ivMain\" destination=\"A8J-br-4wp\" id=\"fHS-YL-S0y\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"eTu-ab-qil\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-25.190839694656489\" y=\"3.8732394366197185\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <namedColor name=\"surface\">\n            <color red=\"0.12549019607843137\" green=\"0.14117647058823529\" blue=\"0.17647058823529413\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Transform/SmartCropping.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Smart Cropping Controller-->\n        <scene sceneID=\"s0d-6b-0kx\">\n            <objects>\n                <viewController storyboardIdentifier=\"SmartCroppingController\" id=\"Y6W-OH-hqX\" customClass=\"SmartCroppingController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"43g-gs-6eR\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"Klv-xh-ICL\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5EZ-qb-Rvc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"603\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"uwN-3H-33K\">\n                                <rect key=\"frame\" x=\"16\" y=\"0.0\" width=\"361\" height=\"569\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"x39-No-9mS\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"259\"/>\n                                        <subviews>\n                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"ski\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"jdt-kM-Gnf\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"259\"/>\n                                                <userDefinedRuntimeAttributes>\n                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                        <integer key=\"value\" value=\"4\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                </userDefinedRuntimeAttributes>\n                                            </imageView>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"bMN-KX-WV1\">\n                                                <rect key=\"frame\" x=\"8\" y=\"221\" width=\"140\" height=\"30\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"c_auto,h_940,w_880\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tRq-fG-6xJ\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"140\" height=\"30\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"10\"/>\n                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" name=\"surface\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"bottom\" secondItem=\"tRq-fG-6xJ\" secondAttribute=\"bottom\" id=\"SaU-wl-2TD\"/>\n                                                    <constraint firstAttribute=\"trailing\" secondItem=\"tRq-fG-6xJ\" secondAttribute=\"trailing\" id=\"VMB-00-E7s\"/>\n                                                    <constraint firstAttribute=\"width\" secondItem=\"bMN-KX-WV1\" secondAttribute=\"height\" multiplier=\"4:1\" constant=\"20\" id=\"Vp0-0A-k8j\"/>\n                                                    <constraint firstItem=\"tRq-fG-6xJ\" firstAttribute=\"top\" secondItem=\"bMN-KX-WV1\" secondAttribute=\"top\" id=\"dOE-As-HXl\"/>\n                                                    <constraint firstItem=\"tRq-fG-6xJ\" firstAttribute=\"leading\" secondItem=\"bMN-KX-WV1\" secondAttribute=\"leading\" id=\"hoD-on-pwU\"/>\n                                                </constraints>\n                                                <userDefinedRuntimeAttributes>\n                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                        <integer key=\"value\" value=\"4\"/>\n                                                    </userDefinedRuntimeAttribute>\n                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                </userDefinedRuntimeAttributes>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"jdt-kM-Gnf\" secondAttribute=\"bottom\" id=\"1gh-AJ-yrl\"/>\n                                            <constraint firstItem=\"bMN-KX-WV1\" firstAttribute=\"leading\" secondItem=\"jdt-kM-Gnf\" secondAttribute=\"leading\" constant=\"8\" id=\"8CV-ab-Eff\"/>\n                                            <constraint firstItem=\"jdt-kM-Gnf\" firstAttribute=\"leading\" secondItem=\"x39-No-9mS\" secondAttribute=\"leading\" id=\"EUh-zB-qYr\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"jdt-kM-Gnf\" secondAttribute=\"trailing\" id=\"Rbn-mE-PsM\"/>\n                                            <constraint firstItem=\"jdt-kM-Gnf\" firstAttribute=\"top\" secondItem=\"x39-No-9mS\" secondAttribute=\"top\" id=\"St3-Oz-YHE\"/>\n                                            <constraint firstItem=\"bMN-KX-WV1\" firstAttribute=\"width\" secondItem=\"x39-No-9mS\" secondAttribute=\"width\" multiplier=\"0.33241\" constant=\"20\" id=\"jd6-fm-vCW\"/>\n                                            <constraint firstItem=\"bMN-KX-WV1\" firstAttribute=\"bottom\" secondItem=\"jdt-kM-Gnf\" secondAttribute=\"bottom\" constant=\"-8\" id=\"lVq-mA-ZQS\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"WEg-mM-byS\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"267\" width=\"361\" height=\"302\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LbZ-Eu-Nb8\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"302\"/>\n                                                <subviews>\n                                                    <view tag=\"8\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OYn-DY-Ws6\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"198.66666666666666\" height=\"302\"/>\n                                                        <subviews>\n                                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacing=\"8\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MyX-DR-4iE\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"198.66666666666666\" height=\"302\"/>\n                                                                <subviews>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"fhS-vq-LK4\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"198.66666666666666\" height=\"102.66666666666667\"/>\n                                                                        <subviews>\n                                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"ski\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"co5-iv-9xK\">\n                                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"198.66666666666666\" height=\"102.66666666666667\"/>\n                                                                                <userDefinedRuntimeAttributes>\n                                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                                        <integer key=\"value\" value=\"4\"/>\n                                                                                    </userDefinedRuntimeAttribute>\n                                                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                                </userDefinedRuntimeAttributes>\n                                                                            </imageView>\n                                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Pxe-dh-NaC\">\n                                                                                <rect key=\"frame\" x=\"8\" y=\"64.666666666666686\" width=\"140\" height=\"30\"/>\n                                                                                <subviews>\n                                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"c_auto,h_340,w_600\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"t5M-FW-woi\">\n                                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"140\" height=\"30\"/>\n                                                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"10\"/>\n                                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                                        <nil key=\"highlightedColor\"/>\n                                                                                    </label>\n                                                                                </subviews>\n                                                                                <color key=\"backgroundColor\" name=\"surface\"/>\n                                                                                <constraints>\n                                                                                    <constraint firstAttribute=\"bottom\" secondItem=\"t5M-FW-woi\" secondAttribute=\"bottom\" id=\"2Ig-y3-DuY\"/>\n                                                                                    <constraint firstAttribute=\"trailing\" secondItem=\"t5M-FW-woi\" secondAttribute=\"trailing\" id=\"PUz-af-rtT\"/>\n                                                                                    <constraint firstAttribute=\"width\" secondItem=\"Pxe-dh-NaC\" secondAttribute=\"height\" multiplier=\"4:1\" constant=\"20\" id=\"R4J-0f-U4K\"/>\n                                                                                    <constraint firstItem=\"t5M-FW-woi\" firstAttribute=\"top\" secondItem=\"Pxe-dh-NaC\" secondAttribute=\"top\" id=\"lvn-Lg-nJP\"/>\n                                                                                    <constraint firstItem=\"t5M-FW-woi\" firstAttribute=\"leading\" secondItem=\"Pxe-dh-NaC\" secondAttribute=\"leading\" id=\"yJN-u1-Z1o\"/>\n                                                                                </constraints>\n                                                                                <userDefinedRuntimeAttributes>\n                                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                                        <integer key=\"value\" value=\"4\"/>\n                                                                                    </userDefinedRuntimeAttribute>\n                                                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                                </userDefinedRuntimeAttributes>\n                                                                            </view>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstAttribute=\"trailing\" secondItem=\"co5-iv-9xK\" secondAttribute=\"trailing\" id=\"5ha-sJ-rHt\"/>\n                                                                            <constraint firstItem=\"co5-iv-9xK\" firstAttribute=\"leading\" secondItem=\"fhS-vq-LK4\" secondAttribute=\"leading\" id=\"RAg-v8-xH9\"/>\n                                                                            <constraint firstItem=\"co5-iv-9xK\" firstAttribute=\"top\" secondItem=\"fhS-vq-LK4\" secondAttribute=\"top\" id=\"hOW-Qd-D4x\"/>\n                                                                            <constraint firstItem=\"Pxe-dh-NaC\" firstAttribute=\"bottom\" secondItem=\"co5-iv-9xK\" secondAttribute=\"bottom\" constant=\"-8\" id=\"lmd-nW-Fs3\"/>\n                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"co5-iv-9xK\" secondAttribute=\"bottom\" id=\"mmQ-qb-RcX\"/>\n                                                                            <constraint firstItem=\"Pxe-dh-NaC\" firstAttribute=\"leading\" secondItem=\"co5-iv-9xK\" secondAttribute=\"leading\" constant=\"8\" id=\"sY6-zo-LXN\"/>\n                                                                            <constraint firstItem=\"Pxe-dh-NaC\" firstAttribute=\"width\" secondItem=\"fhS-vq-LK4\" secondAttribute=\"width\" multiplier=\"0.604027\" constant=\"20\" id=\"x90-px-d4e\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3SM-wx-6xY\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"110.6666666666667\" width=\"198.66666666666666\" height=\"191.33333333333337\"/>\n                                                                        <subviews>\n                                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"ski\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"JCa-2R-DDG\">\n                                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"198.66666666666666\" height=\"191.33333333333334\"/>\n                                                                                <userDefinedRuntimeAttributes>\n                                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                                        <integer key=\"value\" value=\"4\"/>\n                                                                                    </userDefinedRuntimeAttribute>\n                                                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                                </userDefinedRuntimeAttributes>\n                                                                            </imageView>\n                                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Guv-gA-ndz\">\n                                                                                <rect key=\"frame\" x=\"8\" y=\"153.33333333333331\" width=\"140\" height=\"30\"/>\n                                                                                <subviews>\n                                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"c_auto,h_584,w_600\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AEq-kO-hlm\">\n                                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"140\" height=\"30\"/>\n                                                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"10\"/>\n                                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                                        <nil key=\"highlightedColor\"/>\n                                                                                    </label>\n                                                                                </subviews>\n                                                                                <color key=\"backgroundColor\" name=\"surface\"/>\n                                                                                <constraints>\n                                                                                    <constraint firstAttribute=\"width\" secondItem=\"Guv-gA-ndz\" secondAttribute=\"height\" multiplier=\"4:1\" constant=\"20\" id=\"2Ow-MR-O0l\"/>\n                                                                                    <constraint firstAttribute=\"trailing\" secondItem=\"AEq-kO-hlm\" secondAttribute=\"trailing\" id=\"6QO-GZ-Wbp\"/>\n                                                                                    <constraint firstItem=\"AEq-kO-hlm\" firstAttribute=\"top\" secondItem=\"Guv-gA-ndz\" secondAttribute=\"top\" id=\"HZ1-FZ-huC\"/>\n                                                                                    <constraint firstItem=\"AEq-kO-hlm\" firstAttribute=\"leading\" secondItem=\"Guv-gA-ndz\" secondAttribute=\"leading\" id=\"NKt-8p-LmE\"/>\n                                                                                    <constraint firstAttribute=\"bottom\" secondItem=\"AEq-kO-hlm\" secondAttribute=\"bottom\" id=\"xqU-xr-wju\"/>\n                                                                                </constraints>\n                                                                                <userDefinedRuntimeAttributes>\n                                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                                        <integer key=\"value\" value=\"4\"/>\n                                                                                    </userDefinedRuntimeAttribute>\n                                                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                                </userDefinedRuntimeAttributes>\n                                                                            </view>\n                                                                        </subviews>\n                                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <constraints>\n                                                                            <constraint firstItem=\"JCa-2R-DDG\" firstAttribute=\"leading\" secondItem=\"3SM-wx-6xY\" secondAttribute=\"leading\" id=\"8pU-R9-YXo\"/>\n                                                                            <constraint firstItem=\"Guv-gA-ndz\" firstAttribute=\"bottom\" secondItem=\"JCa-2R-DDG\" secondAttribute=\"bottom\" constant=\"-8\" id=\"FeZ-Lc-cWT\"/>\n                                                                            <constraint firstItem=\"JCa-2R-DDG\" firstAttribute=\"top\" secondItem=\"3SM-wx-6xY\" secondAttribute=\"top\" id=\"QoX-r7-hra\"/>\n                                                                            <constraint firstAttribute=\"bottom\" secondItem=\"JCa-2R-DDG\" secondAttribute=\"bottom\" id=\"h2F-Ce-cbk\"/>\n                                                                            <constraint firstItem=\"Guv-gA-ndz\" firstAttribute=\"width\" secondItem=\"3SM-wx-6xY\" secondAttribute=\"width\" multiplier=\"0.604027\" constant=\"20\" id=\"jjP-l6-7Or\"/>\n                                                                            <constraint firstAttribute=\"trailing\" secondItem=\"JCa-2R-DDG\" secondAttribute=\"trailing\" id=\"nkt-H2-KHy\"/>\n                                                                            <constraint firstItem=\"Guv-gA-ndz\" firstAttribute=\"leading\" secondItem=\"JCa-2R-DDG\" secondAttribute=\"leading\" constant=\"8\" id=\"raL-5X-X0Z\"/>\n                                                                        </constraints>\n                                                                    </view>\n                                                                </subviews>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"fhS-vq-LK4\" firstAttribute=\"height\" secondItem=\"MyX-DR-4iE\" secondAttribute=\"height\" multiplier=\"0.34\" id=\"ouW-m9-Fy2\"/>\n                                                                </constraints>\n                                                            </stackView>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"MyX-DR-4iE\" secondAttribute=\"trailing\" id=\"MdT-lA-rLY\"/>\n                                                            <constraint firstItem=\"MyX-DR-4iE\" firstAttribute=\"top\" secondItem=\"OYn-DY-Ws6\" secondAttribute=\"top\" id=\"fsf-R7-4YM\"/>\n                                                            <constraint firstItem=\"MyX-DR-4iE\" firstAttribute=\"leading\" secondItem=\"OYn-DY-Ws6\" secondAttribute=\"leading\" id=\"gdT-LR-BQs\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"MyX-DR-4iE\" secondAttribute=\"bottom\" id=\"mpi-SS-s1G\"/>\n                                                            <constraint firstItem=\"MyX-DR-4iE\" firstAttribute=\"top\" secondItem=\"OYn-DY-Ws6\" secondAttribute=\"top\" id=\"xHB-a8-mWE\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Ppk-nN-Mld\">\n                                                        <rect key=\"frame\" x=\"206.66666666666663\" y=\"0.0\" width=\"154.33333333333337\" height=\"302\"/>\n                                                        <subviews>\n                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"ski\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aY5-E8-vWV\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"154.33333333333334\" height=\"302\"/>\n                                                                <userDefinedRuntimeAttributes>\n                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                        <integer key=\"value\" value=\"4\"/>\n                                                                    </userDefinedRuntimeAttribute>\n                                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                </userDefinedRuntimeAttributes>\n                                                            </imageView>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"HdK-qr-hCc\">\n                                                                <rect key=\"frame\" x=\"8\" y=\"264\" width=\"140\" height=\"30\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"c_auto,h_940,w_460\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"SCN-CS-ib8\">\n                                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"140\" height=\"30\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"10\"/>\n                                                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" name=\"surface\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"SCN-CS-ib8\" firstAttribute=\"top\" secondItem=\"HdK-qr-hCc\" secondAttribute=\"top\" id=\"6td-py-JCv\"/>\n                                                                    <constraint firstItem=\"SCN-CS-ib8\" firstAttribute=\"leading\" secondItem=\"HdK-qr-hCc\" secondAttribute=\"leading\" id=\"XSs-od-Yrm\"/>\n                                                                    <constraint firstAttribute=\"bottom\" secondItem=\"SCN-CS-ib8\" secondAttribute=\"bottom\" id=\"Zil-z8-gT6\"/>\n                                                                    <constraint firstAttribute=\"trailing\" secondItem=\"SCN-CS-ib8\" secondAttribute=\"trailing\" id=\"wdJ-b4-ujv\"/>\n                                                                </constraints>\n                                                                <userDefinedRuntimeAttributes>\n                                                                    <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                        <integer key=\"value\" value=\"4\"/>\n                                                                    </userDefinedRuntimeAttribute>\n                                                                    <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                                </userDefinedRuntimeAttributes>\n                                                            </view>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"HdK-qr-hCc\" firstAttribute=\"bottom\" secondItem=\"aY5-E8-vWV\" secondAttribute=\"bottom\" constant=\"-8\" id=\"1AT-jN-S9A\"/>\n                                                            <constraint firstItem=\"HdK-qr-hCc\" firstAttribute=\"width\" secondItem=\"HdK-qr-hCc\" secondAttribute=\"height\" multiplier=\"4:1\" constant=\"20\" id=\"1MJ-Ub-Tqh\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"aY5-E8-vWV\" secondAttribute=\"bottom\" id=\"CVJ-D0-zOd\"/>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"aY5-E8-vWV\" secondAttribute=\"trailing\" id=\"G4H-sg-mpc\"/>\n                                                            <constraint firstItem=\"aY5-E8-vWV\" firstAttribute=\"leading\" secondItem=\"Ppk-nN-Mld\" secondAttribute=\"leading\" id=\"M9Z-RB-eI8\"/>\n                                                            <constraint firstItem=\"HdK-qr-hCc\" firstAttribute=\"leading\" secondItem=\"aY5-E8-vWV\" secondAttribute=\"leading\" constant=\"8\" id=\"Q2z-fc-Kif\"/>\n                                                            <constraint firstItem=\"HdK-qr-hCc\" firstAttribute=\"width\" secondItem=\"Ppk-nN-Mld\" secondAttribute=\"width\" multiplier=\"0.777538\" constant=\"20\" id=\"syq-Fu-vdw\"/>\n                                                            <constraint firstItem=\"aY5-E8-vWV\" firstAttribute=\"top\" secondItem=\"Ppk-nN-Mld\" secondAttribute=\"top\" id=\"t4B-Jp-Yt6\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"OYn-DY-Ws6\" firstAttribute=\"width\" secondItem=\"LbZ-Eu-Nb8\" secondAttribute=\"width\" multiplier=\"0.55\" id=\"IPh-VP-8pY\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"LbZ-Eu-Nb8\" firstAttribute=\"leading\" secondItem=\"WEg-mM-byS\" secondAttribute=\"leading\" id=\"5nx-EG-IIN\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"LbZ-Eu-Nb8\" secondAttribute=\"bottom\" id=\"byv-CM-uZQ\"/>\n                                            <constraint firstItem=\"LbZ-Eu-Nb8\" firstAttribute=\"top\" secondItem=\"WEg-mM-byS\" secondAttribute=\"top\" id=\"ebI-rG-OYL\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"LbZ-Eu-Nb8\" secondAttribute=\"trailing\" id=\"fv4-yl-fLj\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"x39-No-9mS\" firstAttribute=\"height\" secondItem=\"uwN-3H-33K\" secondAttribute=\"height\" multiplier=\"0.455\" id=\"UsK-q0-dv0\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"uwN-3H-33K\" firstAttribute=\"top\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"top\" id=\"4ht-qm-beB\"/>\n                            <constraint firstItem=\"uwN-3H-33K\" firstAttribute=\"leading\" secondItem=\"5EZ-qb-Rvc\" secondAttribute=\"leading\" constant=\"16\" id=\"Mix-zo-uz5\"/>\n                            <constraint firstItem=\"Klv-xh-ICL\" firstAttribute=\"top\" secondItem=\"uwN-3H-33K\" secondAttribute=\"bottom\" id=\"ujh-ka-uoY\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"uwN-3H-33K\" secondAttribute=\"trailing\" constant=\"16\" id=\"z9a-tN-tVe\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"603\"/>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Ief-a0-LHa\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-25.190839694656489\" y=\"3.8732394366197185\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"ski\" width=\"357\" height=\"274\"/>\n        <namedColor name=\"surface\">\n            <color red=\"0.12549019607843137\" green=\"0.14117647058823529\" blue=\"0.17647058823529413\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Transform/Transform.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"dark\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"collection view cell content view\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Transform View Controller-->\n        <scene sceneID=\"NTP-vI-rvb\">\n            <objects>\n                <viewController storyboardIdentifier=\"TransformViewController\" id=\"muS-dq-Yn9\" customClass=\"TransformViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"aJ0-kU-oa5\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"3i7-br-qyB\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8Em-Jk-9pK\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" spacing=\"10\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"OUc-va-ScB\">\n                                <rect key=\"frame\" x=\"16\" y=\"59\" width=\"361\" height=\"761\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VuT-Ul-TbM\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"593.66666666666663\"/>\n                                        <subviews>\n                                            <containerView opaque=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"wyX-ez-aAV\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"594\"/>\n                                            </containerView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"wyX-ez-aAV\" firstAttribute=\"top\" secondItem=\"VuT-Ul-TbM\" secondAttribute=\"top\" id=\"74m-rd-oC0\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"wyX-ez-aAV\" secondAttribute=\"trailing\" id=\"Vfr-ka-rxZ\"/>\n                                            <constraint firstItem=\"wyX-ez-aAV\" firstAttribute=\"leading\" secondItem=\"VuT-Ul-TbM\" secondAttribute=\"leading\" id=\"dC8-DN-gVo\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"wyX-ez-aAV\" secondAttribute=\"bottom\" id=\"gpa-er-1Wp\"/>\n                                        </constraints>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"z2Q-Eb-hcA\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"603.66666666666663\" width=\"361\" height=\"157.33333333333337\"/>\n                                        <subviews>\n                                            <collectionView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" dataMode=\"prototypes\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"VGr-Pk-Ct6\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"157.33333333333334\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <collectionViewFlowLayout key=\"collectionViewLayout\" scrollDirection=\"horizontal\" minimumLineSpacing=\"0.0\" minimumInteritemSpacing=\"0.0\" id=\"k8I-bE-ixc\">\n                                                    <size key=\"itemSize\" width=\"80\" height=\"116\"/>\n                                                    <size key=\"headerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <size key=\"footerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <inset key=\"sectionInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                                </collectionViewFlowLayout>\n                                                <cells>\n                                                    <collectionViewCell opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" reuseIdentifier=\"TransformCollectionCell\" id=\"5Ga-Bs-Vks\" customClass=\"TransformCollectionCell\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"20.666666666666668\" width=\"80\" height=\"116\"/>\n                                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                        <collectionViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"WW5-cm-ZZT\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"80\" height=\"116\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                                            <subviews>\n                                                                <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"afP-P3-knW\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"80\" height=\"116\"/>\n                                                                </imageView>\n                                                                <view alpha=\"0.5\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"X5a-tC-ROH\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"80\" height=\"116\"/>\n                                                                    <color key=\"backgroundColor\" white=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                </view>\n                                                                <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" fixedFrame=\"YES\" text=\"Smart Cropping\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZjV-aA-x2e\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"-0.33333333333325754\" width=\"80\" height=\"116\"/>\n                                                                    <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"12\"/>\n                                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                    <nil key=\"highlightedColor\"/>\n                                                                </label>\n                                                            </subviews>\n                                                            <constraints>\n                                                                <constraint firstItem=\"X5a-tC-ROH\" firstAttribute=\"leading\" secondItem=\"WW5-cm-ZZT\" secondAttribute=\"leading\" id=\"1YG-7r-lKJ\"/>\n                                                                <constraint firstAttribute=\"trailing\" secondItem=\"X5a-tC-ROH\" secondAttribute=\"trailing\" id=\"58t-S8-to6\"/>\n                                                                <constraint firstItem=\"X5a-tC-ROH\" firstAttribute=\"top\" secondItem=\"WW5-cm-ZZT\" secondAttribute=\"top\" id=\"RyI-cJ-fqe\"/>\n                                                                <constraint firstItem=\"afP-P3-knW\" firstAttribute=\"top\" secondItem=\"WW5-cm-ZZT\" secondAttribute=\"top\" id=\"b5Q-pN-4Un\"/>\n                                                                <constraint firstAttribute=\"trailing\" secondItem=\"afP-P3-knW\" secondAttribute=\"trailing\" id=\"eF2-0h-K5z\"/>\n                                                                <constraint firstAttribute=\"bottom\" secondItem=\"afP-P3-knW\" secondAttribute=\"bottom\" id=\"ii8-T7-PVl\"/>\n                                                                <constraint firstAttribute=\"bottom\" secondItem=\"X5a-tC-ROH\" secondAttribute=\"bottom\" id=\"twp-ap-w0o\"/>\n                                                                <constraint firstItem=\"afP-P3-knW\" firstAttribute=\"leading\" secondItem=\"WW5-cm-ZZT\" secondAttribute=\"leading\" id=\"uEq-tg-y5S\"/>\n                                                            </constraints>\n                                                            <userDefinedRuntimeAttributes>\n                                                                <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                    <integer key=\"value\" value=\"4\"/>\n                                                                </userDefinedRuntimeAttribute>\n                                                                <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBound\" value=\"YES\"/>\n                                                            </userDefinedRuntimeAttributes>\n                                                        </collectionViewCellContentView>\n                                                        <size key=\"customSize\" width=\"80\" height=\"116\"/>\n                                                        <connections>\n                                                            <outlet property=\"ivMain\" destination=\"afP-P3-knW\" id=\"paj-8a-tq1\"/>\n                                                            <outlet property=\"lbMain\" destination=\"ZjV-aA-x2e\" id=\"IVr-f3-rFh\"/>\n                                                        </connections>\n                                                    </collectionViewCell>\n                                                </cells>\n                                            </collectionView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"VGr-Pk-Ct6\" secondAttribute=\"trailing\" id=\"Aqa-eC-QtO\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"VGr-Pk-Ct6\" secondAttribute=\"bottom\" id=\"IKn-oK-rYm\"/>\n                                            <constraint firstItem=\"VGr-Pk-Ct6\" firstAttribute=\"leading\" secondItem=\"z2Q-Eb-hcA\" secondAttribute=\"leading\" id=\"mMG-4g-4ct\"/>\n                                            <constraint firstItem=\"VGr-Pk-Ct6\" firstAttribute=\"top\" secondItem=\"z2Q-Eb-hcA\" secondAttribute=\"top\" id=\"oMV-hZ-R9Q\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"VuT-Ul-TbM\" firstAttribute=\"height\" secondItem=\"OUc-va-ScB\" secondAttribute=\"height\" multiplier=\"0.78\" id=\"uu1-F1-ZaJ\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"OUc-va-ScB\" secondAttribute=\"trailing\" constant=\"16\" id=\"5GV-Wi-Uo8\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"OUc-va-ScB\" secondAttribute=\"bottom\" constant=\"32\" id=\"6Vm-MS-Hwu\"/>\n                            <constraint firstItem=\"OUc-va-ScB\" firstAttribute=\"top\" secondItem=\"aJ0-kU-oa5\" secondAttribute=\"bottom\" id=\"dBo-MZ-wsU\"/>\n                            <constraint firstItem=\"OUc-va-ScB\" firstAttribute=\"leading\" secondItem=\"8Em-Jk-9pK\" secondAttribute=\"leading\" constant=\"16\" id=\"qNi-ET-Ya2\"/>\n                        </constraints>\n                    </view>\n                    <freeformSimulatedSizeMetrics key=\"simulatedDestinationMetrics\"/>\n                    <connections>\n                        <outlet property=\"cvMain\" destination=\"VGr-Pk-Ct6\" id=\"1Jr-lE-LFF\"/>\n                        <outlet property=\"vwContainer\" destination=\"wyX-ez-aAV\" id=\"B8E-fu-hvg\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"HN7-0z-keY\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"129.00763358778624\" y=\"-2.1126760563380285\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Upload/SingleUpload.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"collection view cell content view\" minToolsVersion=\"11.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Single Upload View Controller-->\n        <scene sceneID=\"k9b-fJ-knS\">\n            <objects>\n                <viewController storyboardIdentifier=\"SingleUploadViewController\" id=\"BSq-rX-g6w\" customClass=\"SingleUploadViewController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"1t6-o9-ej4\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"8oL-tI-edL\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"iln-c6-GYU\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"oeh-ia-B96\">\n                                <rect key=\"frame\" x=\"16\" y=\"59\" width=\"361\" height=\"759\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sX3-kw-sr0\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"645\"/>\n                                        <subviews>\n                                            <view alpha=\"0.20000000298023224\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"0Eg-dx-zT8\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"361\" height=\"645\"/>\n                                                <color key=\"backgroundColor\" name=\"primary\"/>\n                                            </view>\n                                            <collectionView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" dataMode=\"prototypes\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"QJ8-yv-TyP\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"8\" width=\"361\" height=\"629\"/>\n                                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                <collectionViewFlowLayout key=\"collectionViewLayout\" automaticEstimatedItemSize=\"YES\" minimumLineSpacing=\"10\" minimumInteritemSpacing=\"10\" id=\"N6X-V6-QDS\">\n                                                    <size key=\"itemSize\" width=\"100\" height=\"100\"/>\n                                                    <size key=\"headerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <size key=\"footerReferenceSize\" width=\"0.0\" height=\"0.0\"/>\n                                                    <inset key=\"sectionInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                                </collectionViewFlowLayout>\n                                                <cells>\n                                                    <collectionViewCell opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" reuseIdentifier=\"uploadCell\" id=\"Wag-4J-5Wa\" customClass=\"SingleUploadCell\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"100\" height=\"100\"/>\n                                                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                                                        <collectionViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" insetsLayoutMarginsFromSafeArea=\"NO\" id=\"Etu-68-QqO\">\n                                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"100\" height=\"100\"/>\n                                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                                            <subviews>\n                                                                <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFill\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"L3c-YS-aCl\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                                                    <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"100\" height=\"100\"/>\n                                                                    <userDefinedRuntimeAttributes>\n                                                                        <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                                            <integer key=\"value\" value=\"4\"/>\n                                                                        </userDefinedRuntimeAttribute>\n                                                                        <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBounds\" value=\"YES\"/>\n                                                                    </userDefinedRuntimeAttributes>\n                                                                </imageView>\n                                                                <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"square.resize\" catalog=\"system\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Qey-lu-Ipa\">\n                                                                    <rect key=\"frame\" x=\"8\" y=\"9.3333333333333321\" width=\"20\" height=\"17.33333333333335\"/>\n                                                                    <color key=\"tintColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                    <constraints>\n                                                                        <constraint firstAttribute=\"width\" constant=\"20\" id=\"onC-ev-Ke2\"/>\n                                                                        <constraint firstAttribute=\"width\" secondItem=\"Qey-lu-Ipa\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"rTR-F7-gNf\"/>\n                                                                    </constraints>\n                                                                </imageView>\n                                                            </subviews>\n                                                            <constraints>\n                                                                <constraint firstItem=\"L3c-YS-aCl\" firstAttribute=\"leading\" secondItem=\"Etu-68-QqO\" secondAttribute=\"leading\" id=\"8yw-rH-U7f\"/>\n                                                                <constraint firstAttribute=\"bottom\" secondItem=\"L3c-YS-aCl\" secondAttribute=\"bottom\" id=\"BFe-m3-5mx\"/>\n                                                                <constraint firstItem=\"Qey-lu-Ipa\" firstAttribute=\"top\" secondItem=\"L3c-YS-aCl\" secondAttribute=\"top\" constant=\"8\" id=\"Dvl-ve-vpC\"/>\n                                                                <constraint firstItem=\"L3c-YS-aCl\" firstAttribute=\"top\" secondItem=\"Etu-68-QqO\" secondAttribute=\"top\" id=\"To2-nm-YFd\"/>\n                                                                <constraint firstItem=\"Qey-lu-Ipa\" firstAttribute=\"leading\" secondItem=\"L3c-YS-aCl\" secondAttribute=\"leading\" constant=\"8\" id=\"bsa-dM-Jcr\"/>\n                                                                <constraint firstAttribute=\"trailing\" secondItem=\"L3c-YS-aCl\" secondAttribute=\"trailing\" id=\"lUv-tp-0K2\"/>\n                                                            </constraints>\n                                                        </collectionViewCellContentView>\n                                                        <connections>\n                                                            <outlet property=\"ivMain\" destination=\"L3c-YS-aCl\" id=\"7rc-F6-XQU\"/>\n                                                        </connections>\n                                                    </collectionViewCell>\n                                                </cells>\n                                            </collectionView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"QJ8-yv-TyP\" firstAttribute=\"leading\" secondItem=\"sX3-kw-sr0\" secondAttribute=\"leading\" id=\"0IZ-La-W1b\"/>\n                                            <constraint firstItem=\"QJ8-yv-TyP\" firstAttribute=\"top\" secondItem=\"sX3-kw-sr0\" secondAttribute=\"top\" constant=\"8\" id=\"Eo1-eU-VtQ\"/>\n                                            <constraint firstItem=\"0Eg-dx-zT8\" firstAttribute=\"leading\" secondItem=\"sX3-kw-sr0\" secondAttribute=\"leading\" id=\"JoD-tk-UxV\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"QJ8-yv-TyP\" secondAttribute=\"bottom\" constant=\"8\" id=\"SQk-iA-3KJ\"/>\n                                            <constraint firstItem=\"0Eg-dx-zT8\" firstAttribute=\"top\" secondItem=\"sX3-kw-sr0\" secondAttribute=\"top\" id=\"cWQ-7x-iWU\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"QJ8-yv-TyP\" secondAttribute=\"trailing\" id=\"ee2-4X-zpp\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"0Eg-dx-zT8\" secondAttribute=\"bottom\" id=\"euL-h5-r2n\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"0Eg-dx-zT8\" secondAttribute=\"trailing\" id=\"fjI-AB-yNc\"/>\n                                        </constraints>\n                                        <userDefinedRuntimeAttributes>\n                                            <userDefinedRuntimeAttribute type=\"number\" keyPath=\"layer.cornerRadius\">\n                                                <integer key=\"value\" value=\"4\"/>\n                                            </userDefinedRuntimeAttribute>\n                                            <userDefinedRuntimeAttribute type=\"boolean\" keyPath=\"layer.masksToBounds\" value=\"YES\"/>\n                                        </userDefinedRuntimeAttributes>\n                                    </view>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eqk-h1-s5q\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"645\" width=\"361\" height=\"114\"/>\n                                        <subviews>\n                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"RZI-Ii-ZYD\">\n                                                <rect key=\"frame\" x=\"16.666666666666657\" y=\"37\" width=\"328\" height=\"40\"/>\n                                                <subviews>\n                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Open Gallery\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"PEf-Ou-BJK\">\n                                                        <rect key=\"frame\" x=\"121\" y=\"11.666666666666629\" width=\"86\" height=\"17\"/>\n                                                        <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"14\"/>\n                                                        <nil key=\"textColor\"/>\n                                                        <nil key=\"highlightedColor\"/>\n                                                    </label>\n                                                </subviews>\n                                                <color key=\"backgroundColor\" name=\"primary\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"width\" secondItem=\"RZI-Ii-ZYD\" secondAttribute=\"height\" multiplier=\"41:5\" id=\"T1f-ZD-y5V\"/>\n                                                    <constraint firstItem=\"PEf-Ou-BJK\" firstAttribute=\"centerY\" secondItem=\"RZI-Ii-ZYD\" secondAttribute=\"centerY\" id=\"pPB-Ij-yOt\"/>\n                                                    <constraint firstItem=\"PEf-Ou-BJK\" firstAttribute=\"centerX\" secondItem=\"RZI-Ii-ZYD\" secondAttribute=\"centerX\" id=\"peg-tt-mpB\"/>\n                                                </constraints>\n                                            </view>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstItem=\"RZI-Ii-ZYD\" firstAttribute=\"centerX\" secondItem=\"eqk-h1-s5q\" secondAttribute=\"centerX\" id=\"5Qu-Ua-ljq\"/>\n                                            <constraint firstItem=\"RZI-Ii-ZYD\" firstAttribute=\"centerY\" secondItem=\"eqk-h1-s5q\" secondAttribute=\"centerY\" id=\"D6a-xf-G9H\"/>\n                                            <constraint firstItem=\"RZI-Ii-ZYD\" firstAttribute=\"width\" secondItem=\"eqk-h1-s5q\" secondAttribute=\"width\" multiplier=\"0.908587\" id=\"vUe-pm-jPj\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"eqk-h1-s5q\" firstAttribute=\"height\" secondItem=\"oeh-ia-B96\" secondAttribute=\"height\" multiplier=\"0.15\" id=\"WTG-Wp-k9h\"/>\n                                </constraints>\n                            </stackView>\n                        </subviews>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"oeh-ia-B96\" firstAttribute=\"leading\" secondItem=\"iln-c6-GYU\" secondAttribute=\"leadingMargin\" id=\"3e0-yG-MI5\"/>\n                            <constraint firstAttribute=\"trailingMargin\" secondItem=\"oeh-ia-B96\" secondAttribute=\"trailing\" id=\"DuN-uB-yeC\"/>\n                            <constraint firstItem=\"8oL-tI-edL\" firstAttribute=\"top\" secondItem=\"oeh-ia-B96\" secondAttribute=\"bottom\" id=\"h4E-Dn-OWY\"/>\n                            <constraint firstItem=\"oeh-ia-B96\" firstAttribute=\"top\" secondItem=\"1t6-o9-ej4\" secondAttribute=\"bottom\" id=\"wIW-d0-87C\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"852\"/>\n                    <connections>\n                        <outlet property=\"cvMain\" destination=\"QJ8-yv-TyP\" id=\"Tky-Xp-y6Y\"/>\n                        <outlet property=\"lbButton\" destination=\"PEf-Ou-BJK\" id=\"Ag7-JA-CXS\"/>\n                        <outlet property=\"vwImage\" destination=\"sX3-kw-sr0\" id=\"kS3-oI-YKw\"/>\n                        <outlet property=\"vwOpenGallery\" destination=\"RZI-Ii-ZYD\" id=\"aYd-wg-GsX\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"D5t-Cy-cN8\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"900\" y=\"1\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"square.resize\" catalog=\"system\" width=\"128\" height=\"116\"/>\n        <namedColor name=\"primary\">\n            <color red=\"0.27450980392156865\" green=\"0.59607843137254901\" blue=\"0.96862745098039216\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Upload/SingleUploadPreview.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Single Upload Preview-->\n        <scene sceneID=\"s0d-6b-0kx\">\n            <objects>\n                <viewController restorationIdentifier=\"SingleUploadPreview\" storyboardIdentifier=\"SingleUploadPreview\" id=\"Y6W-OH-hqX\" customClass=\"SingleUploadPreview\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"5EZ-qb-Rvc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vu1-Va-XLI\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"59\" width=\"393\" height=\"759\"/>\n                                <subviews>\n                                    <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Nvn-9H-oaM\" customClass=\"CLDUIImageView\" customModule=\"Cloudinary\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"759\"/>\n                                    </imageView>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"p3T-i2-w9i\">\n                                        <rect key=\"frame\" x=\"16\" y=\"16\" width=\"40\" height=\"40\"/>\n                                        <subviews>\n                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"square.and.arrow.up\" catalog=\"system\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Un6-RV-8xo\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"-2.3333333333333321\" width=\"40\" height=\"42\"/>\n                                                <color key=\"tintColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                            </imageView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"width\" constant=\"40\" id=\"3N0-B5-evh\"/>\n                                            <constraint firstItem=\"Un6-RV-8xo\" firstAttribute=\"leading\" secondItem=\"p3T-i2-w9i\" secondAttribute=\"leading\" id=\"BBC-RG-Faf\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"Un6-RV-8xo\" secondAttribute=\"trailing\" id=\"D0A-9s-z1X\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"Un6-RV-8xo\" secondAttribute=\"bottom\" id=\"Jtx-ky-JzC\"/>\n                                            <constraint firstItem=\"Un6-RV-8xo\" firstAttribute=\"top\" secondItem=\"p3T-i2-w9i\" secondAttribute=\"top\" id=\"Q9u-Xn-fGQ\"/>\n                                            <constraint firstAttribute=\"width\" secondItem=\"p3T-i2-w9i\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"mup-gz-MY7\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <constraints>\n                                    <constraint firstItem=\"p3T-i2-w9i\" firstAttribute=\"leading\" secondItem=\"Nvn-9H-oaM\" secondAttribute=\"leading\" constant=\"16\" id=\"A3J-He-OI7\"/>\n                                    <constraint firstItem=\"Nvn-9H-oaM\" firstAttribute=\"leading\" secondItem=\"Vu1-Va-XLI\" secondAttribute=\"leading\" id=\"Gin-vc-LN1\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"Nvn-9H-oaM\" secondAttribute=\"bottom\" id=\"Qfj-w9-gMM\"/>\n                                    <constraint firstItem=\"p3T-i2-w9i\" firstAttribute=\"top\" secondItem=\"Nvn-9H-oaM\" secondAttribute=\"top\" constant=\"16\" id=\"TI6-Wh-T4O\"/>\n                                    <constraint firstItem=\"Nvn-9H-oaM\" firstAttribute=\"top\" secondItem=\"Vu1-Va-XLI\" secondAttribute=\"top\" id=\"V6Q-3A-BcY\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"Nvn-9H-oaM\" secondAttribute=\"trailing\" id=\"hi2-F4-PYm\"/>\n                                </constraints>\n                            </view>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"vDu-zF-Fre\"/>\n                        <color key=\"backgroundColor\" name=\"surface\"/>\n                        <constraints>\n                            <constraint firstItem=\"Vu1-Va-XLI\" firstAttribute=\"top\" secondItem=\"vDu-zF-Fre\" secondAttribute=\"top\" id=\"6k1-bm-1nD\"/>\n                            <constraint firstItem=\"vDu-zF-Fre\" firstAttribute=\"trailing\" secondItem=\"Vu1-Va-XLI\" secondAttribute=\"trailing\" id=\"ISy-Sx-Hvp\"/>\n                            <constraint firstItem=\"vDu-zF-Fre\" firstAttribute=\"bottom\" secondItem=\"Vu1-Va-XLI\" secondAttribute=\"bottom\" id=\"ofj-jC-miD\"/>\n                            <constraint firstItem=\"Vu1-Va-XLI\" firstAttribute=\"leading\" secondItem=\"vDu-zF-Fre\" secondAttribute=\"leading\" id=\"pY3-mL-tVt\"/>\n                        </constraints>\n                    </view>\n                    <connections>\n                        <outlet property=\"ivMain\" destination=\"Nvn-9H-oaM\" id=\"jpO-BB-bUY\"/>\n                        <outlet property=\"vwImage\" destination=\"Vu1-Va-XLI\" id=\"Egh-KO-sro\"/>\n                        <outlet property=\"vwShare\" destination=\"p3T-i2-w9i\" id=\"PPu-IY-0Du\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"Ief-a0-LHa\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"94\" y=\"4\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"square.and.arrow.up\" catalog=\"system\" width=\"108\" height=\"128\"/>\n        <namedColor name=\"surface\">\n            <color red=\"0.12549019607843137\" green=\"0.14117647058823529\" blue=\"0.17647058823529413\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Upload/UploadChoice.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Upload Choice Controller-->\n        <scene sceneID=\"C4L-FY-SLj\">\n            <objects>\n                <viewController storyboardIdentifier=\"UploadChoiceController\" id=\"jud-sL-eES\" customClass=\"UploadChoiceController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"e4w-rX-3i2\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"pZ8-Cf-h7L\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Kru-22-Ukc\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" flexibleMaxX=\"YES\" flexibleMaxY=\"YES\"/>\n                        <subviews>\n                            <containerView opaque=\"NO\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"98m-pD-Wtx\">\n                                <rect key=\"frame\" x=\"16\" y=\"59\" width=\"361\" height=\"759\"/>\n                            </containerView>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"72U-r2-b7a\"/>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstItem=\"pZ8-Cf-h7L\" firstAttribute=\"top\" secondItem=\"98m-pD-Wtx\" secondAttribute=\"bottom\" id=\"DyJ-ky-9MI\"/>\n                            <constraint firstAttribute=\"trailingMargin\" secondItem=\"98m-pD-Wtx\" secondAttribute=\"trailing\" id=\"SdN-mo-gPy\"/>\n                            <constraint firstItem=\"98m-pD-Wtx\" firstAttribute=\"top\" secondItem=\"e4w-rX-3i2\" secondAttribute=\"bottom\" id=\"mKy-z8-lfV\"/>\n                            <constraint firstItem=\"98m-pD-Wtx\" firstAttribute=\"leading\" secondItem=\"Kru-22-Ukc\" secondAttribute=\"leadingMargin\" id=\"oaF-TW-Fvo\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"852\"/>\n                    <connections>\n                        <outlet property=\"vwContainer\" destination=\"98m-pD-Wtx\" id=\"QJU-YN-0ge\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"RAd-SV-jW3\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-69\" y=\"2\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary/Views/Upload/UploadDoesNotExist.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"22505\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\">\n    <device id=\"retina6_12\" orientation=\"portrait\" appearance=\"light\"/>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"22504\"/>\n        <capability name=\"Named colors\" minToolsVersion=\"9.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Upload Does Not Exist Controller-->\n        <scene sceneID=\"1xr-J4-npJ\">\n            <objects>\n                <viewController storyboardIdentifier=\"UploadDoesNotExistController\" id=\"hcL-Px-DDI\" customClass=\"UploadDoesNotExistController\" customModule=\"Cloudinary_Sample_App\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"jSG-xe-2Bq\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"PYa-XH-EJv\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"MDz-4f-7c5\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"393\" height=\"852\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <view alpha=\"0.20000000000000001\" contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LXz-Gu-2bd\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"59\" width=\"393\" height=\"759\"/>\n                                <color key=\"backgroundColor\" name=\"primary\"/>\n                            </view>\n                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"M7N-e8-QTh\">\n                                <rect key=\"frame\" x=\"16\" y=\"59\" width=\"361\" height=\"753\"/>\n                                <subviews>\n                                    <activityIndicatorView hidden=\"YES\" opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" animating=\"YES\" style=\"large\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yqy-D8-7oQ\">\n                                        <rect key=\"frame\" x=\"162\" y=\"358\" width=\"37\" height=\"37\"/>\n                                        <color key=\"color\" name=\"primary\"/>\n                                    </activityIndicatorView>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"AXP-fP-O24\">\n                                        <rect key=\"frame\" x=\"68\" y=\"266\" width=\"225\" height=\"221\"/>\n                                        <subviews>\n                                            <stackView opaque=\"NO\" contentMode=\"scaleToFill\" axis=\"vertical\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"hC2-dU-udD\">\n                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"225\" height=\"221\"/>\n                                                <subviews>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Rmt-Ft-tEZ\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"225\" height=\"106\"/>\n                                                        <subviews>\n                                                            <imageView clipsSubviews=\"YES\" userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"upload_missing\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"3Wq-Ef-JpX\">\n                                                                <rect key=\"frame\" x=\"48.333333333333343\" y=\"-11\" width=\"128.33333333333334\" height=\"128\"/>\n                                                                <constraints>\n                                                                    <constraint firstAttribute=\"width\" secondItem=\"3Wq-Ef-JpX\" secondAttribute=\"height\" multiplier=\"1:1\" id=\"258-Ra-Xb9\"/>\n                                                                </constraints>\n                                                            </imageView>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"3Wq-Ef-JpX\" firstAttribute=\"centerX\" secondItem=\"Rmt-Ft-tEZ\" secondAttribute=\"centerX\" id=\"mf3-qf-XdA\"/>\n                                                            <constraint firstItem=\"3Wq-Ef-JpX\" firstAttribute=\"height\" secondItem=\"Rmt-Ft-tEZ\" secondAttribute=\"height\" multiplier=\"1.20755\" id=\"tKh-MH-Vgx\"/>\n                                                            <constraint firstItem=\"3Wq-Ef-JpX\" firstAttribute=\"centerY\" secondItem=\"Rmt-Ft-tEZ\" secondAttribute=\"centerY\" id=\"zcE-7K-j71\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"KHg-jF-RfM\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"106\" width=\"225\" height=\"51\"/>\n                                                        <subviews>\n                                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Upload your image now and let the magic begin!\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"CfS-to-hm9\">\n                                                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"225\" height=\"51\"/>\n                                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"16\"/>\n                                                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                                <nil key=\"highlightedColor\"/>\n                                                            </label>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstAttribute=\"trailing\" secondItem=\"CfS-to-hm9\" secondAttribute=\"trailing\" id=\"7Ba-2x-rcs\"/>\n                                                            <constraint firstItem=\"CfS-to-hm9\" firstAttribute=\"top\" secondItem=\"KHg-jF-RfM\" secondAttribute=\"top\" id=\"7EY-b8-xPk\"/>\n                                                            <constraint firstItem=\"CfS-to-hm9\" firstAttribute=\"leading\" secondItem=\"KHg-jF-RfM\" secondAttribute=\"leading\" id=\"i3m-gH-g8Z\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"CfS-to-hm9\" secondAttribute=\"bottom\" id=\"y7h-Q5-ZzM\"/>\n                                                        </constraints>\n                                                    </view>\n                                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Nl2-Bp-xYL\">\n                                                        <rect key=\"frame\" x=\"0.0\" y=\"157\" width=\"225\" height=\"64\"/>\n                                                        <subviews>\n                                                            <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"NFf-sM-tvJ\">\n                                                                <rect key=\"frame\" x=\"39.333333333333329\" y=\"21\" width=\"146.33333333333337\" height=\"43\"/>\n                                                                <subviews>\n                                                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Upload Image\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"5RE-Iq-oLk\">\n                                                                        <rect key=\"frame\" x=\"20.333333333333321\" y=\"11.333333333333369\" width=\"105.66666666666669\" height=\"20.333333333333329\"/>\n                                                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                                        <nil key=\"textColor\"/>\n                                                                        <nil key=\"highlightedColor\"/>\n                                                                    </label>\n                                                                </subviews>\n                                                                <color key=\"backgroundColor\" name=\"primary\"/>\n                                                                <constraints>\n                                                                    <constraint firstItem=\"5RE-Iq-oLk\" firstAttribute=\"centerX\" secondItem=\"NFf-sM-tvJ\" secondAttribute=\"centerX\" id=\"AGa-ZV-3Jv\"/>\n                                                                    <constraint firstAttribute=\"width\" secondItem=\"NFf-sM-tvJ\" secondAttribute=\"height\" multiplier=\"75:22\" id=\"Tla-PI-bs0\"/>\n                                                                    <constraint firstItem=\"5RE-Iq-oLk\" firstAttribute=\"centerY\" secondItem=\"NFf-sM-tvJ\" secondAttribute=\"centerY\" id=\"cJO-Tu-MDS\"/>\n                                                                </constraints>\n                                                            </view>\n                                                        </subviews>\n                                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                        <constraints>\n                                                            <constraint firstItem=\"NFf-sM-tvJ\" firstAttribute=\"centerX\" secondItem=\"Nl2-Bp-xYL\" secondAttribute=\"centerX\" id=\"UMO-e9-9Mb\"/>\n                                                            <constraint firstItem=\"NFf-sM-tvJ\" firstAttribute=\"width\" secondItem=\"Nl2-Bp-xYL\" secondAttribute=\"width\" multiplier=\"0.65\" id=\"Vbx-tc-H2M\"/>\n                                                            <constraint firstAttribute=\"bottom\" secondItem=\"NFf-sM-tvJ\" secondAttribute=\"bottom\" id=\"aQ6-go-oqs\"/>\n                                                        </constraints>\n                                                    </view>\n                                                </subviews>\n                                                <constraints>\n                                                    <constraint firstItem=\"KHg-jF-RfM\" firstAttribute=\"height\" secondItem=\"hC2-dU-udD\" secondAttribute=\"height\" multiplier=\"0.23\" id=\"7Qi-CB-6K9\"/>\n                                                    <constraint firstItem=\"Rmt-Ft-tEZ\" firstAttribute=\"height\" secondItem=\"hC2-dU-udD\" secondAttribute=\"height\" multiplier=\"0.48\" id=\"w6z-PZ-fqv\"/>\n                                                </constraints>\n                                            </stackView>\n                                        </subviews>\n                                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <constraints>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"hC2-dU-udD\" secondAttribute=\"bottom\" id=\"C7D-aM-RCE\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"hC2-dU-udD\" secondAttribute=\"trailing\" id=\"JU4-Rf-2lG\"/>\n                                            <constraint firstItem=\"hC2-dU-udD\" firstAttribute=\"top\" secondItem=\"AXP-fP-O24\" secondAttribute=\"top\" id=\"W9h-9a-3ci\"/>\n                                            <constraint firstItem=\"hC2-dU-udD\" firstAttribute=\"leading\" secondItem=\"AXP-fP-O24\" secondAttribute=\"leading\" id=\"q0T-km-SfZ\"/>\n                                            <constraint firstAttribute=\"width\" secondItem=\"AXP-fP-O24\" secondAttribute=\"height\" multiplier=\"225:221\" id=\"rAc-6U-uh1\"/>\n                                        </constraints>\n                                    </view>\n                                    <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Please add the upload preset “ios_sample” to your account for successful upload\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" numberOfLines=\"2\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ZsZ-JJ-1Hz\">\n                                        <rect key=\"frame\" x=\"16\" y=\"703.33333333333337\" width=\"329\" height=\"33.666666666666629\"/>\n                                        <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"14\"/>\n                                        <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                        <nil key=\"highlightedColor\"/>\n                                    </label>\n                                </subviews>\n                                <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"ZsZ-JJ-1Hz\" secondAttribute=\"trailing\" constant=\"16\" id=\"4p4-MW-XM4\"/>\n                                    <constraint firstItem=\"yqy-D8-7oQ\" firstAttribute=\"centerY\" secondItem=\"M7N-e8-QTh\" secondAttribute=\"centerY\" id=\"E0m-dg-Uqm\"/>\n                                    <constraint firstItem=\"AXP-fP-O24\" firstAttribute=\"centerX\" secondItem=\"M7N-e8-QTh\" secondAttribute=\"centerX\" id=\"GbA-5K-fbD\"/>\n                                    <constraint firstItem=\"yqy-D8-7oQ\" firstAttribute=\"centerX\" secondItem=\"M7N-e8-QTh\" secondAttribute=\"centerX\" id=\"Otx-2t-OSP\"/>\n                                    <constraint firstItem=\"AXP-fP-O24\" firstAttribute=\"width\" secondItem=\"M7N-e8-QTh\" secondAttribute=\"width\" multiplier=\"0.623269\" id=\"g1X-Ae-C3m\"/>\n                                    <constraint firstItem=\"AXP-fP-O24\" firstAttribute=\"centerY\" secondItem=\"M7N-e8-QTh\" secondAttribute=\"centerY\" id=\"i7c-Kd-DH4\"/>\n                                    <constraint firstItem=\"ZsZ-JJ-1Hz\" firstAttribute=\"leading\" secondItem=\"M7N-e8-QTh\" secondAttribute=\"leading\" constant=\"16\" id=\"wmH-JG-DNl\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"ZsZ-JJ-1Hz\" secondAttribute=\"bottom\" constant=\"16\" id=\"z6g-ct-hU8\"/>\n                                </constraints>\n                            </view>\n                        </subviews>\n                        <viewLayoutGuide key=\"safeArea\" id=\"K36-NL-8oB\"/>\n                        <color key=\"backgroundColor\" white=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        <constraints>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"M7N-e8-QTh\" secondAttribute=\"bottom\" constant=\"40\" id=\"1Xx-Wc-auJ\"/>\n                            <constraint firstItem=\"M7N-e8-QTh\" firstAttribute=\"leading\" secondItem=\"K36-NL-8oB\" secondAttribute=\"leading\" constant=\"16\" id=\"2SW-WQ-lto\"/>\n                            <constraint firstItem=\"LXz-Gu-2bd\" firstAttribute=\"top\" secondItem=\"K36-NL-8oB\" secondAttribute=\"top\" id=\"6iU-hD-1Cn\"/>\n                            <constraint firstItem=\"M7N-e8-QTh\" firstAttribute=\"top\" secondItem=\"K36-NL-8oB\" secondAttribute=\"top\" id=\"adT-ys-b5G\"/>\n                            <constraint firstItem=\"K36-NL-8oB\" firstAttribute=\"trailing\" secondItem=\"LXz-Gu-2bd\" secondAttribute=\"trailing\" id=\"gSf-8J-rfA\"/>\n                            <constraint firstItem=\"LXz-Gu-2bd\" firstAttribute=\"leading\" secondItem=\"K36-NL-8oB\" secondAttribute=\"leading\" id=\"jFT-5V-xDd\"/>\n                            <constraint firstAttribute=\"trailing\" secondItem=\"M7N-e8-QTh\" secondAttribute=\"trailing\" constant=\"16\" id=\"tIx-Mb-mOj\"/>\n                            <constraint firstItem=\"K36-NL-8oB\" firstAttribute=\"bottom\" secondItem=\"LXz-Gu-2bd\" secondAttribute=\"bottom\" id=\"uID-TV-f0V\"/>\n                        </constraints>\n                    </view>\n                    <size key=\"freeformSize\" width=\"393\" height=\"852\"/>\n                    <connections>\n                        <outlet property=\"aiLoading\" destination=\"yqy-D8-7oQ\" id=\"sfy-HY-hGq\"/>\n                        <outlet property=\"lbUploadButton\" destination=\"5RE-Iq-oLk\" id=\"aW9-u2-mbM\"/>\n                        <outlet property=\"lbUploadContainer\" destination=\"CfS-to-hm9\" id=\"TxD-PF-gvx\"/>\n                        <outlet property=\"vwUpload\" destination=\"NFf-sM-tvJ\" id=\"HcV-rd-CdO\"/>\n                        <outlet property=\"vwUploadContainer\" destination=\"AXP-fP-O24\" id=\"V2M-qE-qg0\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"8Rl-Js-vnT\" userLabel=\"First Responder\" customClass=\"UIResponder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"0.76335877862595414\" y=\"3.5211267605633805\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"upload_missing\" width=\"125\" height=\"107\"/>\n        <namedColor name=\"primary\">\n            <color red=\"0.27450980392156865\" green=\"0.59607843137254901\" blue=\"0.96862745098039216\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n        </namedColor>\n    </resources>\n</document>\n"
  },
  {
    "path": "Example/Cloudinary.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\t1E635A3E25A756870003E9D3 /* ObjcBaseTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E635A3D25A756860003E9D3 /* ObjcBaseTestCase.m */; };\n\t\t1E635A7025A757DA0003E9D3 /* BaseMockProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E635A6F25A757DA0003E9D3 /* BaseMockProvider.swift */; };\n\t\t1E635A7F25A7585E0003E9D3 /* MockProviderQualityAnalysis.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E635A7825A7585E0003E9D3 /* MockProviderQualityAnalysis.swift */; };\n\t\t1E635A8025A7585E0003E9D3 /* ObjcUploaderQualityAnalysisTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E635A7925A7585E0003E9D3 /* ObjcUploaderQualityAnalysisTests.m */; };\n\t\t1E635A8125A7585E0003E9D3 /* QualityAnalysisUploadResultParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E635A7A25A7585E0003E9D3 /* QualityAnalysisUploadResultParserTests.swift */; };\n\t\t1E635A8225A7585E0003E9D3 /* ObjcQualityAnalysisExplicitResultParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E635A7B25A7585E0003E9D3 /* ObjcQualityAnalysisExplicitResultParserTests.m */; };\n\t\t1E635A8325A7585E0003E9D3 /* UploaderQualityAnalysisTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E635A7C25A7585E0003E9D3 /* UploaderQualityAnalysisTests.swift */; };\n\t\t1E635A8425A7585E0003E9D3 /* QualityAnalysisExplicitResultParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E635A7D25A7585E0003E9D3 /* QualityAnalysisExplicitResultParserTests.swift */; };\n\t\t1E635A8525A7585E0003E9D3 /* ObjcQualityAnalysisUploadResultParserTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E635A7E25A7585E0003E9D3 /* ObjcQualityAnalysisUploadResultParserTests.m */; };\n\t\t270C1BF723FBBA3C00A503C3 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 270C1BF623FBBA3C00A503C3 /* LICENSE */; };\n\t\t272C517F242B6C360093AB1B /* SessionManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C513E242B6C340093AB1B /* SessionManagerTests.swift */; };\n\t\t272C5180242B6C360093AB1B /* FileManager+CloudinaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C513F242B6C340093AB1B /* FileManager+CloudinaryTests.swift */; };\n\t\t272C5181242B6C360093AB1B /* AuthenticationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C5140242B6C340093AB1B /* AuthenticationTests.swift */; };\n\t\t272C5182242B6C360093AB1B /* RequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C5141242B6C350093AB1B /* RequestTests.swift */; };\n\t\t272C5183242B6C360093AB1B /* SessionDelegateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C5142242B6C350093AB1B /* SessionDelegateTests.swift */; };\n\t\t272C5185242B6C360093AB1B /* ResponseSerializationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C5144242B6C350093AB1B /* ResponseSerializationTests.swift */; };\n\t\t272C5186242B6C360093AB1B /* MultipartFormDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C5145242B6C350093AB1B /* MultipartFormDataTests.swift */; };\n\t\t272C5187242B6C360093AB1B /* URLProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C5146242B6C350093AB1B /* URLProtocolTests.swift */; };\n\t\t272C5189242B6C360093AB1B /* ResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C5148242B6C350093AB1B /* ResponseTests.swift */; };\n\t\t272C518C242B6C360093AB1B /* BaseTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C514B242B6C350093AB1B /* BaseTestCase.swift */; };\n\t\t272C518D242B6C360093AB1B /* unicorn.png in Resources */ = {isa = PBXBuildFile; fileRef = 272C514E242B6C350093AB1B /* unicorn.png */; };\n\t\t272C518E242B6C360093AB1B /* rainbow.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 272C514F242B6C350093AB1B /* rainbow.jpg */; };\n\t\t272C518F242B6C360093AB1B /* invalid.data in Resources */ = {isa = PBXBuildFile; fileRef = 272C5152242B6C350093AB1B /* invalid.data */; };\n\t\t272C5190242B6C360093AB1B /* valid.data in Resources */ = {isa = PBXBuildFile; fileRef = 272C5153242B6C350093AB1B /* valid.data */; };\n\t\t272C5191242B6C360093AB1B /* empty.data in Resources */ = {isa = PBXBuildFile; fileRef = 272C5154242B6C350093AB1B /* empty.data */; };\n\t\t272C5192242B6C360093AB1B /* empty_data.json in Resources */ = {isa = PBXBuildFile; fileRef = 272C5156242B6C350093AB1B /* empty_data.json */; };\n\t\t272C5193242B6C360093AB1B /* valid_data.json in Resources */ = {isa = PBXBuildFile; fileRef = 272C5157242B6C350093AB1B /* valid_data.json */; };\n\t\t272C5194242B6C360093AB1B /* invalid_data.json in Resources */ = {isa = PBXBuildFile; fileRef = 272C5158242B6C350093AB1B /* invalid_data.json */; };\n\t\t272C5195242B6C360093AB1B /* utf8_string.txt in Resources */ = {isa = PBXBuildFile; fileRef = 272C515A242B6C350093AB1B /* utf8_string.txt */; };\n\t\t272C5196242B6C360093AB1B /* utf32_string.txt in Resources */ = {isa = PBXBuildFile; fileRef = 272C515B242B6C350093AB1B /* utf32_string.txt */; };\n\t\t272C5197242B6C360093AB1B /* empty_string.txt in Resources */ = {isa = PBXBuildFile; fileRef = 272C515C242B6C350093AB1B /* empty_string.txt */; };\n\t\t272C51B0242B6C360093AB1B /* UploadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C5179242B6C360093AB1B /* UploadTests.swift */; };\n\t\t272C51B1242B6C360093AB1B /* CacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C517A242B6C360093AB1B /* CacheTests.swift */; };\n\t\t272C51B3242B6C360093AB1B /* CLDNError+CloudinaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C517C242B6C360093AB1B /* CLDNError+CloudinaryTests.swift */; };\n\t\t272C51B4242B6C360093AB1B /* ResultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C517D242B6C360093AB1B /* ResultTests.swift */; };\n\t\t272C51B5242B6C360093AB1B /* ParameterEncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C517E242B6C360093AB1B /* ParameterEncodingTests.swift */; };\n\t\t274C6D2D23FBAF5E0090BC40 /* CryptoUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D1323FBAF5E0090BC40 /* CryptoUtilsTests.swift */; };\n\t\t274C6D2E23FBAF5E0090BC40 /* PreprocessTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D1423FBAF5E0090BC40 /* PreprocessTests.swift */; };\n\t\t274C6D2F23FBAF5E0090BC40 /* FileUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D1523FBAF5E0090BC40 /* FileUtilsTests.swift */; };\n\t\t274C6D3023FBAF5E0090BC40 /* UrlTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D1723FBAF5E0090BC40 /* UrlTests.m */; };\n\t\t274C6D3123FBAF5E0090BC40 /* UrlTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D1823FBAF5E0090BC40 /* UrlTests.swift */; };\n\t\t274C6D3223FBAF5E0090BC40 /* UIBaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D1A23FBAF5E0090BC40 /* UIBaseTest.swift */; };\n\t\t274C6D3323FBAF5E0090BC40 /* UIButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D1B23FBAF5E0090BC40 /* UIButtonTests.swift */; };\n\t\t274C6D3423FBAF5E0090BC40 /* UIImageViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D1C23FBAF5E0090BC40 /* UIImageViewTests.swift */; };\n\t\t274C6D3623FBAF5E0090BC40 /* UploaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D1F23FBAF5E0090BC40 /* UploaderTests.swift */; };\n\t\t274C6D3723FBAF5E0090BC40 /* ManagementApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D2023FBAF5E0090BC40 /* ManagementApiTests.swift */; };\n\t\t274C6D3823FBAF5E0090BC40 /* DownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D2123FBAF5E0090BC40 /* DownloaderTests.swift */; };\n\t\t274C6D3923FBAF5E0090BC40 /* StringUtilsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274C6D2223FBAF5E0090BC40 /* StringUtilsTest.swift */; };\n\t\t274C6D3A23FBAF5E0090BC40 /* borderCollie.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 274C6D2523FBAF5E0090BC40 /* borderCollie.jpg */; };\n\t\t274C6D3B23FBAF5E0090BC40 /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = 274C6D2623FBAF5E0090BC40 /* logo.png */; };\n\t\t274C6D3C23FBAF5E0090BC40 /* docx.docx in Resources */ = {isa = PBXBuildFile; fileRef = 274C6D2823FBAF5E0090BC40 /* docx.docx */; };\n\t\t274C6D3D23FBAF5E0090BC40 /* pdf.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 274C6D2923FBAF5E0090BC40 /* pdf.pdf */; };\n\t\t274C6D3E23FBAF5E0090BC40 /* dog.mov in Resources */ = {isa = PBXBuildFile; fileRef = 274C6D2B23FBAF5E0090BC40 /* dog.mov */; };\n\t\t274C6D3F23FBAF5E0090BC40 /* dog.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 274C6D2C23FBAF5E0090BC40 /* dog.mp4 */; };\n\t\t27BC1FAE2431C3F6000AFC2C /* CLDNDataResponse+CloudinaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27BC1FAD2431C3F6000AFC2C /* CLDNDataResponse+CloudinaryTests.swift */; };\n\t\t27BC1FB02431C48D000AFC2C /* CLDNResult+CloudinaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27BC1FAF2431C48D000AFC2C /* CLDNResult+CloudinaryTests.swift */; };\n\t\t5B1EF16C5EA94AD09F6C22C2 /* Pods_Cloudinary_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D07C87FEDB1F561D123D6873 /* Pods_Cloudinary_Tests.framework */; };\n\t\t5D4D8C2D246098F900AE9C96 /* CLDConditionExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D4D8C2B246098BA00AE9C96 /* CLDConditionExpressionTests.swift */; };\n\t\t5D4D8C2E24609C1400AE9C96 /* ValidationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 272C514A242B6C350093AB1B /* ValidationTests.swift */; };\n\t\t5D53A9512488CE23005C14AB /* CLDConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D53A94F2488CE23005C14AB /* CLDConfigurationTests.swift */; };\n\t\t5D53A9522488CE23005C14AB /* CLDConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D53A9502488CE23005C14AB /* CLDConfigurationTests.m */; };\n\t\t5D7C2DCF245E93F7007E95F7 /* CLDExpressionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D7C2DCE245E93F7007E95F7 /* CLDExpressionTests.swift */; };\n\t\t5DB2D29824FFE32500001845 /* UploaderWidgetConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2D29624FFE32500001845 /* UploaderWidgetConfigurationTests.swift */; };\n\t\t5DB2D29924FFE32500001845 /* UploaderWidgetConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DB2D29724FFE32500001845 /* UploaderWidgetConfigurationTests.m */; };\n\t\t5DE4EC202469919A00F6C8D6 /* CLDTransformationBaselineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DE4EC1E2469919700F6C8D6 /* CLDTransformationBaselineTests.swift */; };\n\t\t9753E077581D46FC1463D265 /* Pods_Cloudinary_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7EAA36BF6CA4E5748DFCD320 /* Pods_Cloudinary_Example.framework */; };\n\t\tB60F3C222D4B86AF00160FFC /* TestableCloudinary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B60F3C212D4B86AF00160FFC /* TestableCloudinary.swift */; };\n\t\tB64120BD2C48ED3F005A5495 /* SingleUploadCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64120BC2C48ED3F005A5495 /* SingleUploadCell.swift */; };\n\t\tB64120BF2C48ED69005A5495 /* SingleUploadCollectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64120BE2C48ED69005A5495 /* SingleUploadCollectionController.swift */; };\n\t\tB64120C12C48ED83005A5495 /* SingleUploadCollectionLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64120C02C48ED83005A5495 /* SingleUploadCollectionLayout.swift */; };\n\t\tB64120C42C48EE76005A5495 /* AssetItems+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64120C32C48EE76005A5495 /* AssetItems+CoreDataClass.swift */; };\n\t\tB64120C62C48EEC7005A5495 /* AssetItems+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64120C52C48EEC7005A5495 /* AssetItems+CoreDataProperties.swift */; };\n\t\tB64120C82C48EED7005A5495 /* AssetModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64120C72C48EED7005A5495 /* AssetModel.swift */; };\n\t\tB64120CB2C48EF10005A5495 /* AssetModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B64120C92C48EF10005A5495 /* AssetModel.xcdatamodeld */; };\n\t\tB64120CD2C48EF22005A5495 /* CoreDataHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64120CC2C48EF22005A5495 /* CoreDataHelper.swift */; };\n\t\tB64120CF2C48F049005A5495 /* SingleUploadPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64120CE2C48F049005A5495 /* SingleUploadPreview.swift */; };\n\t\tB64120D12C48F0EC005A5495 /* SingleUploadPreview.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64120D02C48F0EC005A5495 /* SingleUploadPreview.storyboard */; };\n\t\tB64ED1E22B8C933B00BE653E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1632B8C933900BE653E /* AppDelegate.swift */; };\n\t\tB64ED1E32B8C933B00BE653E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1642B8C933900BE653E /* GoogleService-Info.plist */; };\n\t\tB64ED1E52B8C933B00BE653E /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1672B8C933A00BE653E /* Colors.xcassets */; };\n\t\tB64ED1E62B8C933B00BE653E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1682B8C933A00BE653E /* Assets.xcassets */; };\n\t\tB64ED1E72B8C933B00BE653E /* VideoFeedCollectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED16C2B8C933A00BE653E /* VideoFeedCollectionController.swift */; };\n\t\tB64ED1E82B8C933B00BE653E /* VideoFeedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED16E2B8C933A00BE653E /* VideoFeedCell.swift */; };\n\t\tB64ED1E92B8C933B00BE653E /* OptimizationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1712B8C933A00BE653E /* OptimizationViewController.swift */; };\n\t\tB64ED1EA2B8C933B00BE653E /* TransformCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1732B8C933A00BE653E /* TransformCollectionCell.swift */; };\n\t\tB64ED1EB2B8C933B00BE653E /* TransformViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1742B8C933A00BE653E /* TransformViewController.swift */; };\n\t\tB64ED1EC2B8C933B00BE653E /* TransformationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1752B8C933A00BE653E /* TransformationCell.swift */; };\n\t\tB64ED1ED2B8C933B00BE653E /* RevealImageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1772B8C933A00BE653E /* RevealImageController.swift */; };\n\t\tB64ED1EE2B8C933B00BE653E /* DeliveryTransformCollectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1782B8C933A00BE653E /* DeliveryTransformCollectionController.swift */; };\n\t\tB64ED1EF2B8C933B00BE653E /* TransformCollectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1792B8C933A00BE653E /* TransformCollectionController.swift */; };\n\t\tB64ED1F02B8C933B00BE653E /* SmartCroppingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED17B2B8C933A00BE653E /* SmartCroppingController.swift */; };\n\t\tB64ED1F12B8C933B00BE653E /* UseCaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED17D2B8C933A00BE653E /* UseCaseCell.swift */; };\n\t\tB64ED1F22B8C933B00BE653E /* UseCaseCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED17E2B8C933A00BE653E /* UseCaseCollectionCell.swift */; };\n\t\tB64ED1F32B8C933B00BE653E /* ConditionalProductViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1802B8C933A00BE653E /* ConditionalProductViewController.swift */; };\n\t\tB64ED1F42B8C933B00BE653E /* NormalizingProductAssetsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1812B8C933A00BE653E /* NormalizingProductAssetsViewController.swift */; };\n\t\tB64ED1F52B8C933B00BE653E /* UseCasesCollectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1822B8C933A00BE653E /* UseCasesCollectionController.swift */; };\n\t\tB64ED1F62B8C933B00BE653E /* DeliveryUseCasesCollectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1832B8C933A00BE653E /* DeliveryUseCasesCollectionController.swift */; };\n\t\tB64ED1F72B8C933B00BE653E /* UseCasesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1842B8C933A00BE653E /* UseCasesViewController.swift */; };\n\t\tB64ED1F82B8C933B00BE653E /* DeliveryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1852B8C933A00BE653E /* DeliveryViewController.swift */; };\n\t\tB64ED1F92B8C933B00BE653E /* UploadChoiceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1872B8C933A00BE653E /* UploadChoiceController.swift */; };\n\t\tB64ED1FA2B8C933B00BE653E /* InnerUploadFrame.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1882B8C933A00BE653E /* InnerUploadFrame.swift */; };\n\t\tB64ED1FB2B8C933B00BE653E /* SingleUploadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1892B8C933A00BE653E /* SingleUploadViewController.swift */; };\n\t\tB64ED1FC2B8C933B00BE653E /* UploadViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED18A2B8C933A00BE653E /* UploadViewController.swift */; };\n\t\tB64ED1FD2B8C933B00BE653E /* UploadNoCloudController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED18B2B8C933A00BE653E /* UploadNoCloudController.swift */; };\n\t\tB64ED1FE2B8C933B00BE653E /* UploadDoesNotExistController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED18D2B8C933A00BE653E /* UploadDoesNotExistController.swift */; };\n\t\tB64ED1FF2B8C933B00BE653E /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED18E2B8C933A00BE653E /* MainViewController.swift */; };\n\t\tB64ED2002B8C933B00BE653E /* video_links.plist in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1912B8C933A00BE653E /* video_links.plist */; };\n\t\tB64ED2012B8C933B00BE653E /* VideoSocialOverlaysController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1932B8C933A00BE653E /* VideoSocialOverlaysController.swift */; };\n\t\tB64ED2022B8C933B00BE653E /* VideoFeedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1942B8C933A00BE653E /* VideoFeedViewController.swift */; };\n\t\tB64ED2032B8C933B00BE653E /* MainPageController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1952B8C933A00BE653E /* MainPageController.swift */; };\n\t\tB64ED2042B8C933B00BE653E /* VideoFeedContainerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1962B8C933A00BE653E /* VideoFeedContainerController.swift */; };\n\t\tB64ED2052B8C933B00BE653E /* VideoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1972B8C933A00BE653E /* VideoViewController.swift */; };\n\t\tB64ED2062B8C933B00BE653E /* VideoFeedController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1982B8C933A00BE653E /* VideoFeedController.swift */; };\n\t\tB64ED2072B8C933B00BE653E /* VideoHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED19A2B8C933A00BE653E /* VideoHelper.swift */; };\n\t\tB64ED2082B8C933B00BE653E /* SplashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED19B2B8C933A00BE653E /* SplashViewController.swift */; };\n\t\tB64ED2092B8C933B00BE653E /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED19D2B8C933A00BE653E /* BaseViewController.swift */; };\n\t\tB64ED20A2B8C933B00BE653E /* WidgetsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED19F2B8C933A00BE653E /* WidgetsViewController.swift */; };\n\t\tB64ED20B2B8C933B00BE653E /* ImageWidgetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1A02B8C933A00BE653E /* ImageWidgetViewController.swift */; };\n\t\tB64ED20C2B8C933B00BE653E /* UploadWidgetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1A12B8C933A00BE653E /* UploadWidgetViewController.swift */; };\n\t\tB64ED20E2B8C933B00BE653E /* Toolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1A52B8C933A00BE653E /* Toolbar.swift */; };\n\t\tB64ED20F2B8C933B00BE653E /* Toolbar.xib in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1A62B8C933A00BE653E /* Toolbar.xib */; };\n\t\tB64ED2102B8C933B00BE653E /* ToolbarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1A82B8C933A00BE653E /* ToolbarItem.swift */; };\n\t\tB64ED2112B8C933B00BE653E /* ToolbarItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1A92B8C933A00BE653E /* ToolbarItem.xib */; };\n\t\tB64ED2122B8C933B00BE653E /* RevealImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1AA2B8C933A00BE653E /* RevealImageView.swift */; };\n\t\tB64ED2132B8C933B00BE653E /* UploadLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1AC2B8C933A00BE653E /* UploadLoadingView.swift */; };\n\t\tB64ED2142B8C933B00BE653E /* UploadLoadingView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1AD2B8C933A00BE653E /* UploadLoadingView.xib */; };\n\t\tB64ED2152B8C933B00BE653E /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1AE2B8C933A00BE653E /* GradientView.swift */; };\n\t\tB64ED2162B8C933B00BE653E /* VideoFeed.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1B22B8C933A00BE653E /* VideoFeed.storyboard */; };\n\t\tB64ED2172B8C933B00BE653E /* VideoSocialOverlays.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1B42B8C933A00BE653E /* VideoSocialOverlays.storyboard */; };\n\t\tB64ED2182B8C933B00BE653E /* Video.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1B52B8C933A00BE653E /* Video.storyboard */; };\n\t\tB64ED2192B8C933B00BE653E /* Delivery.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1B72B8C933A00BE653E /* Delivery.storyboard */; };\n\t\tB64ED21A2B8C933B00BE653E /* Optimization.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1B82B8C933A00BE653E /* Optimization.storyboard */; };\n\t\tB64ED21B2B8C933B00BE653E /* UseCases.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1B92B8C933A00BE653E /* UseCases.storyboard */; };\n\t\tB64ED21C2B8C933B00BE653E /* NormalizingProductAssets.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1BB2B8C933A00BE653E /* NormalizingProductAssets.storyboard */; };\n\t\tB64ED21D2B8C933B00BE653E /* ConditionalProduct.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1BC2B8C933A00BE653E /* ConditionalProduct.storyboard */; };\n\t\tB64ED21E2B8C933B00BE653E /* Base.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1BE2B8C933A00BE653E /* Base.storyboard */; };\n\t\tB64ED21F2B8C933B00BE653E /* ImageWidget.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1C02B8C933A00BE653E /* ImageWidget.storyboard */; };\n\t\tB64ED2212B8C933B00BE653E /* Widgets.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1C22B8C933A00BE653E /* Widgets.storyboard */; };\n\t\tB64ED2222B8C933B00BE653E /* InnerUploadFrame.xib in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1C42B8C933A00BE653E /* InnerUploadFrame.xib */; };\n\t\tB64ED2232B8C933B00BE653E /* Upload.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1C52B8C933A00BE653E /* Upload.storyboard */; };\n\t\tB64ED2242B8C933B00BE653E /* UploadNoCloud.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1C62B8C933A00BE653E /* UploadNoCloud.storyboard */; };\n\t\tB64ED2252B8C933B00BE653E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1C72B8C933A00BE653E /* LaunchScreen.storyboard */; };\n\t\tB64ED2262B8C933B00BE653E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1C92B8C933A00BE653E /* Main.storyboard */; };\n\t\tB64ED2272B8C933B00BE653E /* Splash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1CB2B8C933A00BE653E /* Splash.storyboard */; };\n\t\tB64ED2282B8C933B00BE653E /* SmartCropping.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1CD2B8C933A00BE653E /* SmartCropping.storyboard */; };\n\t\tB64ED2292B8C933B00BE653E /* RevealImage.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1CE2B8C933A00BE653E /* RevealImage.storyboard */; };\n\t\tB64ED22A2B8C933B00BE653E /* Transform.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1CF2B8C933A00BE653E /* Transform.storyboard */; };\n\t\tB64ED22B2B8C933B00BE653E /* UploadDoesNotExist.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1D12B8C933A00BE653E /* UploadDoesNotExist.storyboard */; };\n\t\tB64ED22C2B8C933B00BE653E /* SingleUpload.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1D22B8C933A00BE653E /* SingleUpload.storyboard */; };\n\t\tB64ED22D2B8C933B00BE653E /* UploadChoice.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64ED1D32B8C933A00BE653E /* UploadChoice.storyboard */; };\n\t\tB64ED22E2B8C933B00BE653E /* CloudinaryHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1D52B8C933A00BE653E /* CloudinaryHelper.swift */; };\n\t\tB64ED22F2B8C933B00BE653E /* FileUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1D62B8C933A00BE653E /* FileUtils.swift */; };\n\t\tB64ED2302B8C933B00BE653E /* Double+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1D82B8C933B00BE653E /* Double+Extension.swift */; };\n\t\tB64ED2312B8C933B00BE653E /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1D92B8C933B00BE653E /* SceneDelegate.swift */; };\n\t\tB64ED2322B8C933B00BE653E /* ImageHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1DB2B8C933B00BE653E /* ImageHelper.swift */; };\n\t\tB64ED2332B8C933B00BE653E /* AnimationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1DC2B8C933B00BE653E /* AnimationHelper.swift */; };\n\t\tB64ED2342B8C933B00BE653E /* EventsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1DE2B8C933B00BE653E /* EventsHandler.swift */; };\n\t\tB64ED2352B8C933B00BE653E /* FirebaseEventsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1DF2B8C933B00BE653E /* FirebaseEventsHandler.swift */; };\n\t\tB64ED2362B8C933B00BE653E /* EventObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1E02B8C933B00BE653E /* EventObject.swift */; };\n\t\tB64ED2372B8C933B00BE653E /* EventsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B64ED1E12B8C933B00BE653E /* EventsProvider.swift */; };\n\t\tB64F0DDD2BC6541000B94590 /* UploadWidget.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B64F0DDC2BC6541000B94590 /* UploadWidget.storyboard */; };\n\t\tB67476152B8CA0D2006ED6C2 /* IntegrateAIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B67476142B8CA0D2006ED6C2 /* IntegrateAIViewController.swift */; };\n\t\tB67476172B8CA0EF006ED6C2 /* IntegrateAI.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B67476162B8CA0EF006ED6C2 /* IntegrateAI.storyboard */; };\n\t\tB694AAF32B308C3C00075041 /* VideoEventsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B694AAF22B308C3C00075041 /* VideoEventsTests.swift */; };\n\t\tB694AAF52B308C5A00075041 /* VideoEventsManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B694AAF42B308C5A00075041 /* VideoEventsManagerTests.swift */; };\n\t\tB6AF51632D4A2A430037965A /* NetworkTestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AF51622D4A2A430037965A /* NetworkTestUtils.swift */; };\n\t\tB6B4C49F2C56152700C9B604 /* VideoPreprocessTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B4C49E2C56152700C9B604 /* VideoPreprocessTests.swift */; };\n\t\tB6C2D4882A72741B00AA0039 /* CLDVideoPlayerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6C2D4872A72741B00AA0039 /* CLDVideoPlayerTests.swift */; };\n\t\tB6F11F3D288FC20900A895CD /* CLDAnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6F11F3C288FC20900A895CD /* CLDAnalyticsTests.swift */; };\n\t\tD7119CE3246C7C8100F6B3ED /* CLDConditionExpressionHelpersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7119CE2246C7C8100F6B3ED /* CLDConditionExpressionHelpersTests.swift */; };\n\t\tD7173498258296CE006F34CD /* WidgetUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7173497258296CE006F34CD /* WidgetUITests.swift */; };\n\t\tD71ADD9C247D976500235AD4 /* CryptoUtilsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D71ADD9B247D976500235AD4 /* CryptoUtilsTests.m */; };\n\t\tD71B78FE24680743004AA28E /* CLDTransformationVariablesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71B78FD24680743004AA28E /* CLDTransformationVariablesTests.swift */; };\n\t\tD71B790024680773004AA28E /* CLDTransformationExpressionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71B78FF24680773004AA28E /* CLDTransformationExpressionsTests.swift */; };\n\t\tD71B7902246808EE004AA28E /* CLDTransformationConditionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71B7901246808EE004AA28E /* CLDTransformationConditionsTests.swift */; };\n\t\tD7289C7F258A9CB5004DBD29 /* dog2.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = D7289C7E258A9CB5004DBD29 /* dog2.mp4 */; };\n\t\tD7289C81258A9D0B004DBD29 /* UploaderWidgetAssetContainerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7289C80258A9D0B004DBD29 /* UploaderWidgetAssetContainerTests.swift */; };\n\t\tD7289C87258A9E18004DBD29 /* UploaderWidgetVideoControlsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7289C83258A9E18004DBD29 /* UploaderWidgetVideoControlsTests.swift */; };\n\t\tD7289C88258A9E18004DBD29 /* UploaderWidgetVideoPlayerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7289C84258A9E18004DBD29 /* UploaderWidgetVideoPlayerTests.swift */; };\n\t\tD7289C89258A9E18004DBD29 /* UploaderWidgetVideoDisplayLinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7289C85258A9E18004DBD29 /* UploaderWidgetVideoDisplayLinkTests.swift */; };\n\t\tD7289C8A258A9E18004DBD29 /* UploaderWidgetVideoViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7289C86258A9E18004DBD29 /* UploaderWidgetVideoViewTests.swift */; };\n\t\tD73117582473D7A30051AAFC /* CLDExpressionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D73117572473D7A30051AAFC /* CLDExpressionTests.m */; };\n\t\tD731175A247415340051AAFC /* CLDConditionExpressionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D7311759247415340051AAFC /* CLDConditionExpressionTests.m */; };\n\t\tD731175C24741FBE0051AAFC /* CLDTransformationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D731175B24741FBE0051AAFC /* CLDTransformationTests.m */; };\n\t\tD73DBB0A258BA0550002E7E5 /* dog2.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = D7289C7E258A9CB5004DBD29 /* dog2.mp4 */; };\n\t\tD73DBB0B258BA0570002E7E5 /* dog.mov in Resources */ = {isa = PBXBuildFile; fileRef = 274C6D2B23FBAF5E0090BC40 /* dog.mov */; };\n\t\tD73DBB0C258BA05A0002E7E5 /* dog.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 274C6D2C23FBAF5E0090BC40 /* dog.mp4 */; };\n\t\tD7519FAC25E2693A006839B1 /* CLDCloudinaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7519FAA25E2693A006839B1 /* CLDCloudinaryTests.swift */; };\n\t\tD7519FAD25E2693A006839B1 /* CLDCloudinaryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D7519FAB25E2693A006839B1 /* CLDCloudinaryTests.m */; };\n\t\tD7519FEC25E26BE9006839B1 /* DownloaderAssetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7519FEB25E26BE9006839B1 /* DownloaderAssetTests.swift */; };\n\t\tD7567064255D661F005B65D3 /* UploaderWidgetViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7567063255D661F005B65D3 /* UploaderWidgetViewControllerTests.swift */; };\n\t\tD7788A3824DC482C00B63EB7 /* borderCollieCropped.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D7788A3724DC482C00B63EB7 /* borderCollieCropped.jpg */; };\n\t\tD7788A9424E29BEC00B63EB7 /* borderCollieRotatedJpg.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D7788A9224E29BEC00B63EB7 /* borderCollieRotatedJpg.jpg */; };\n\t\tD7788A9524E29BEC00B63EB7 /* borderCollieRotatedPng.png in Resources */ = {isa = PBXBuildFile; fileRef = D7788A9324E29BEC00B63EB7 /* borderCollieRotatedPng.png */; };\n\t\tD779B69724B7117300E496EB /* UploaderAccessibilityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D779B69424B7117200E496EB /* UploaderAccessibilityTests.swift */; };\n\t\tD779B69824B7117300E496EB /* UploaderAccessibilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D779B69524B7117200E496EB /* UploaderAccessibilityTests.m */; };\n\t\tD7866141248FE34A0099DE8C /* textImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D7866140248FE34A0099DE8C /* textImage.jpg */; };\n\t\tD79AE385244CC1D7004F2439 /* CLDTransformationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D79AE384244CC1D7004F2439 /* CLDTransformationTests.swift */; };\n\t\tD79AE387244DF1E7004F2439 /* CLDVariableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D79AE386244DF1E7004F2439 /* CLDVariableTests.swift */; };\n\t\tD79AE39C24585533004F2439 /* CLDVariableTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D79AE39B24585533004F2439 /* CLDVariableTests.m */; };\n\t\tD7E79DC924B515260082288A /* UploaderOcrTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E79DC324B515260082288A /* UploaderOcrTests.swift */; };\n\t\tD7E79DCA24B515260082288A /* OcrMockProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E79DC424B515260082288A /* OcrMockProvider.swift */; };\n\t\tD7E79DCB24B515260082288A /* ExplicitMockOcrTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D7E79DC524B515260082288A /* ExplicitMockOcrTests.m */; };\n\t\tD7E79DCC24B515260082288A /* UploaderMockOcrTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D7E79DC624B515260082288A /* UploaderMockOcrTests.m */; };\n\t\tD7E79DCD24B515260082288A /* UploaderMockOcrTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E79DC724B515260082288A /* UploaderMockOcrTests.swift */; };\n\t\tD7E79DCE24B515260082288A /* ExplicitMockOcrTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E79DC824B515260082288A /* ExplicitMockOcrTests.swift */; };\n\t\tD7E79DD124B515650082288A /* UploadRequestParamsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E79DD024B515650082288A /* UploadRequestParamsTests.swift */; };\n\t\tD7EC161F2592261200DD7611 /* borderCollieRotatedJpgUnderIOS12.jpg in Resources */ = {isa = PBXBuildFile; fileRef = D7EC161E2592261200DD7611 /* borderCollieRotatedJpgUnderIOS12.jpg */; };\n\t\tD7EC162125922BA200DD7611 /* borderCollieRotatedPngUnderIOS12.png in Resources */ = {isa = PBXBuildFile; fileRef = D7EC162025922BA200DD7611 /* borderCollieRotatedPngUnderIOS12.png */; };\n\t\tD7EF05AB255D8B8E00F93827 /* NetworkBaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF05A8255D8B8E00F93827 /* NetworkBaseTest.swift */; };\n\t\tD7EF05AC255D8B8E00F93827 /* NetworkBaseTestObjc.m in Sources */ = {isa = PBXBuildFile; fileRef = D7EF05AA255D8B8E00F93827 /* NetworkBaseTestObjc.m */; };\n\t\tD7EF05B0255D8C1900F93827 /* UploaderWidgetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7EF05AE255D8C1900F93827 /* UploaderWidgetTests.swift */; };\n\t\tD7EF05B1255D8C1900F93827 /* UploaderWidgetTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D7EF05AF255D8C1900F93827 /* UploaderWidgetTests.m */; };\n\t\tD7F34F2F2504F48C00C282B1 /* UploaderWidgetCollectionCellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7F34F2E2504F48C00C282B1 /* UploaderWidgetCollectionCellTests.swift */; };\n\t\tD7F34F3125052FBD00C282B1 /* UploaderWidgetPreviewViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7F34F3025052FBD00C282B1 /* UploaderWidgetPreviewViewControllerTests.swift */; };\n\t\tD7F34F3325052FE700C282B1 /* WidgetBaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7F34F3225052FE700C282B1 /* WidgetBaseTest.swift */; };\n\t\tD7F34F9125120E0D00C282B1 /* UploaderWidgetEditViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7F34F9025120E0C00C282B1 /* UploaderWidgetEditViewControllerTests.swift */; };\n\t\tD7F3D46024DC3BAB002C1D27 /* PreprocessUploaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7F3D45F24DC3BAB002C1D27 /* PreprocessUploaderTests.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t607FACE61AFB9204008FA782 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 607FACC81AFB9204008FA782 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 607FACCF1AFB9204008FA782;\n\t\t\tremoteInfo = Cloudinary;\n\t\t};\n\t\tD717349A258296CE006F34CD /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 607FACC81AFB9204008FA782 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 607FACCF1AFB9204008FA782;\n\t\t\tremoteInfo = Cloudinary_Example;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t1E635A3C25A756860003E9D3 /* ObjcBaseTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjcBaseTestCase.h; sourceTree = \"<group>\"; };\n\t\t1E635A3D25A756860003E9D3 /* ObjcBaseTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjcBaseTestCase.m; sourceTree = \"<group>\"; };\n\t\t1E635A6F25A757DA0003E9D3 /* BaseMockProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseMockProvider.swift; sourceTree = \"<group>\"; };\n\t\t1E635A7825A7585E0003E9D3 /* MockProviderQualityAnalysis.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockProviderQualityAnalysis.swift; sourceTree = \"<group>\"; };\n\t\t1E635A7925A7585E0003E9D3 /* ObjcUploaderQualityAnalysisTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjcUploaderQualityAnalysisTests.m; sourceTree = \"<group>\"; };\n\t\t1E635A7A25A7585E0003E9D3 /* QualityAnalysisUploadResultParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QualityAnalysisUploadResultParserTests.swift; sourceTree = \"<group>\"; };\n\t\t1E635A7B25A7585E0003E9D3 /* ObjcQualityAnalysisExplicitResultParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjcQualityAnalysisExplicitResultParserTests.m; sourceTree = \"<group>\"; };\n\t\t1E635A7C25A7585E0003E9D3 /* UploaderQualityAnalysisTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderQualityAnalysisTests.swift; sourceTree = \"<group>\"; };\n\t\t1E635A7D25A7585E0003E9D3 /* QualityAnalysisExplicitResultParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QualityAnalysisExplicitResultParserTests.swift; sourceTree = \"<group>\"; };\n\t\t1E635A7E25A7585E0003E9D3 /* ObjcQualityAnalysisUploadResultParserTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ObjcQualityAnalysisUploadResultParserTests.m; sourceTree = \"<group>\"; };\n\t\t270C1BF623FBBA3C00A503C3 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = \"<group>\"; };\n\t\t272C513E242B6C340093AB1B /* SessionManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionManagerTests.swift; sourceTree = \"<group>\"; };\n\t\t272C513F242B6C340093AB1B /* FileManager+CloudinaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"FileManager+CloudinaryTests.swift\"; sourceTree = \"<group>\"; };\n\t\t272C5140242B6C340093AB1B /* AuthenticationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationTests.swift; sourceTree = \"<group>\"; };\n\t\t272C5141242B6C350093AB1B /* RequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestTests.swift; sourceTree = \"<group>\"; };\n\t\t272C5142242B6C350093AB1B /* SessionDelegateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionDelegateTests.swift; sourceTree = \"<group>\"; };\n\t\t272C5144242B6C350093AB1B /* ResponseSerializationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseSerializationTests.swift; sourceTree = \"<group>\"; };\n\t\t272C5145242B6C350093AB1B /* MultipartFormDataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultipartFormDataTests.swift; sourceTree = \"<group>\"; };\n\t\t272C5146242B6C350093AB1B /* URLProtocolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLProtocolTests.swift; sourceTree = \"<group>\"; };\n\t\t272C5148242B6C350093AB1B /* ResponseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseTests.swift; sourceTree = \"<group>\"; };\n\t\t272C514A242B6C350093AB1B /* ValidationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationTests.swift; sourceTree = \"<group>\"; };\n\t\t272C514B242B6C350093AB1B /* BaseTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTestCase.swift; sourceTree = \"<group>\"; };\n\t\t272C514E242B6C350093AB1B /* unicorn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = unicorn.png; sourceTree = \"<group>\"; };\n\t\t272C514F242B6C350093AB1B /* rainbow.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = rainbow.jpg; sourceTree = \"<group>\"; };\n\t\t272C5152242B6C350093AB1B /* invalid.data */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = invalid.data; sourceTree = \"<group>\"; };\n\t\t272C5153242B6C350093AB1B /* valid.data */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = valid.data; sourceTree = \"<group>\"; };\n\t\t272C5154242B6C350093AB1B /* empty.data */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = empty.data; sourceTree = \"<group>\"; };\n\t\t272C5156242B6C350093AB1B /* empty_data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = empty_data.json; sourceTree = \"<group>\"; };\n\t\t272C5157242B6C350093AB1B /* valid_data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = valid_data.json; sourceTree = \"<group>\"; };\n\t\t272C5158242B6C350093AB1B /* invalid_data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = invalid_data.json; sourceTree = \"<group>\"; };\n\t\t272C515A242B6C350093AB1B /* utf8_string.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = utf8_string.txt; sourceTree = \"<group>\"; };\n\t\t272C515B242B6C350093AB1B /* utf32_string.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = utf32_string.txt; sourceTree = \"<group>\"; };\n\t\t272C515C242B6C350093AB1B /* empty_string.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = empty_string.txt; sourceTree = \"<group>\"; };\n\t\t272C5179242B6C360093AB1B /* UploadTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadTests.swift; sourceTree = \"<group>\"; };\n\t\t272C517A242B6C360093AB1B /* CacheTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CacheTests.swift; sourceTree = \"<group>\"; };\n\t\t272C517C242B6C360093AB1B /* CLDNError+CloudinaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"CLDNError+CloudinaryTests.swift\"; sourceTree = \"<group>\"; };\n\t\t272C517D242B6C360093AB1B /* ResultTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResultTests.swift; sourceTree = \"<group>\"; };\n\t\t272C517E242B6C360093AB1B /* ParameterEncodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParameterEncodingTests.swift; sourceTree = \"<group>\"; };\n\t\t274C6D1323FBAF5E0090BC40 /* CryptoUtilsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CryptoUtilsTests.swift; sourceTree = \"<group>\"; };\n\t\t274C6D1423FBAF5E0090BC40 /* PreprocessTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreprocessTests.swift; sourceTree = \"<group>\"; };\n\t\t274C6D1523FBAF5E0090BC40 /* FileUtilsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtilsTests.swift; sourceTree = \"<group>\"; };\n\t\t274C6D1723FBAF5E0090BC40 /* UrlTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UrlTests.m; sourceTree = \"<group>\"; };\n\t\t274C6D1823FBAF5E0090BC40 /* UrlTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UrlTests.swift; sourceTree = \"<group>\"; };\n\t\t274C6D1A23FBAF5E0090BC40 /* UIBaseTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIBaseTest.swift; sourceTree = \"<group>\"; };\n\t\t274C6D1B23FBAF5E0090BC40 /* UIButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIButtonTests.swift; sourceTree = \"<group>\"; };\n\t\t274C6D1C23FBAF5E0090BC40 /* UIImageViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIImageViewTests.swift; sourceTree = \"<group>\"; };\n\t\t274C6D1F23FBAF5E0090BC40 /* UploaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderTests.swift; sourceTree = \"<group>\"; };\n\t\t274C6D2023FBAF5E0090BC40 /* ManagementApiTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagementApiTests.swift; sourceTree = \"<group>\"; };\n\t\t274C6D2123FBAF5E0090BC40 /* DownloaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloaderTests.swift; sourceTree = \"<group>\"; };\n\t\t274C6D2223FBAF5E0090BC40 /* StringUtilsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringUtilsTest.swift; sourceTree = \"<group>\"; };\n\t\t274C6D2523FBAF5E0090BC40 /* borderCollie.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = borderCollie.jpg; sourceTree = \"<group>\"; };\n\t\t274C6D2623FBAF5E0090BC40 /* logo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = logo.png; sourceTree = \"<group>\"; };\n\t\t274C6D2823FBAF5E0090BC40 /* docx.docx */ = {isa = PBXFileReference; lastKnownFileType = file; path = docx.docx; sourceTree = \"<group>\"; };\n\t\t274C6D2923FBAF5E0090BC40 /* pdf.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = pdf.pdf; sourceTree = \"<group>\"; };\n\t\t274C6D2B23FBAF5E0090BC40 /* dog.mov */ = {isa = PBXFileReference; lastKnownFileType = video.quicktime; path = dog.mov; sourceTree = \"<group>\"; };\n\t\t274C6D2C23FBAF5E0090BC40 /* dog.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = dog.mp4; sourceTree = \"<group>\"; };\n\t\t27BC1FAD2431C3F6000AFC2C /* CLDNDataResponse+CloudinaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"CLDNDataResponse+CloudinaryTests.swift\"; sourceTree = \"<group>\"; };\n\t\t27BC1FAF2431C48D000AFC2C /* CLDNResult+CloudinaryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"CLDNResult+CloudinaryTests.swift\"; sourceTree = \"<group>\"; };\n\t\t2F5D96AD5982EFEBDEE91350 /* Pods-Cloudinary_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Cloudinary_Tests.debug.xcconfig\"; path = \"Target Support Files/Pods-Cloudinary_Tests/Pods-Cloudinary_Tests.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\t5D4D8C2B246098BA00AE9C96 /* CLDConditionExpressionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLDConditionExpressionTests.swift; sourceTree = \"<group>\"; };\n\t\t5D53A94F2488CE23005C14AB /* CLDConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLDConfigurationTests.swift; sourceTree = \"<group>\"; };\n\t\t5D53A9502488CE23005C14AB /* CLDConfigurationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CLDConfigurationTests.m; sourceTree = \"<group>\"; };\n\t\t5D7C2DCE245E93F7007E95F7 /* CLDExpressionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDExpressionTests.swift; sourceTree = \"<group>\"; };\n\t\t5DB2D29624FFE32500001845 /* UploaderWidgetConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetConfigurationTests.swift; sourceTree = \"<group>\"; };\n\t\t5DB2D29724FFE32500001845 /* UploaderWidgetConfigurationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UploaderWidgetConfigurationTests.m; sourceTree = \"<group>\"; };\n\t\t5DE4EC1E2469919700F6C8D6 /* CLDTransformationBaselineTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLDTransformationBaselineTests.swift; sourceTree = \"<group>\"; };\n\t\t607FACD01AFB9204008FA782 /* Cloudinary_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Cloudinary_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t607FACE51AFB9204008FA782 /* Cloudinary_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Cloudinary_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t7EAA36BF6CA4E5748DFCD320 /* Pods_Cloudinary_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cloudinary_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tAA2F53C389142220209152BA /* Cloudinary.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; name = Cloudinary.podspec; path = ../Cloudinary.podspec; sourceTree = \"<group>\"; };\n\t\tB60F3C212D4B86AF00160FFC /* TestableCloudinary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestableCloudinary.swift; sourceTree = \"<group>\"; };\n\t\tB60F3C232D4B86E200160FFC /* Cloudinary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cloudinary.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tB64120BC2C48ED3F005A5495 /* SingleUploadCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleUploadCell.swift; sourceTree = \"<group>\"; };\n\t\tB64120BE2C48ED69005A5495 /* SingleUploadCollectionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleUploadCollectionController.swift; sourceTree = \"<group>\"; };\n\t\tB64120C02C48ED83005A5495 /* SingleUploadCollectionLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleUploadCollectionLayout.swift; sourceTree = \"<group>\"; };\n\t\tB64120C32C48EE76005A5495 /* AssetItems+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"AssetItems+CoreDataClass.swift\"; sourceTree = \"<group>\"; };\n\t\tB64120C52C48EEC7005A5495 /* AssetItems+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"AssetItems+CoreDataProperties.swift\"; sourceTree = \"<group>\"; };\n\t\tB64120C72C48EED7005A5495 /* AssetModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetModel.swift; sourceTree = \"<group>\"; };\n\t\tB64120CA2C48EF10005A5495 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = \"<group>\"; };\n\t\tB64120CC2C48EF22005A5495 /* CoreDataHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataHelper.swift; sourceTree = \"<group>\"; };\n\t\tB64120CE2C48F049005A5495 /* SingleUploadPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleUploadPreview.swift; sourceTree = \"<group>\"; };\n\t\tB64120D02C48F0EC005A5495 /* SingleUploadPreview.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SingleUploadPreview.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1622B8C933900BE653E /* Cloudinary_Example-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = \"Cloudinary_Example-Bridging-Header.h\"; sourceTree = \"<group>\"; };\n\t\tB64ED1632B8C933900BE653E /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1642B8C933900BE653E /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = \"GoogleService-Info.plist\"; sourceTree = \"<group>\"; };\n\t\tB64ED1672B8C933A00BE653E /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = \"<group>\"; };\n\t\tB64ED1682B8C933A00BE653E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tB64ED16C2B8C933A00BE653E /* VideoFeedCollectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoFeedCollectionController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED16E2B8C933A00BE653E /* VideoFeedCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoFeedCell.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1712B8C933A00BE653E /* OptimizationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptimizationViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1732B8C933A00BE653E /* TransformCollectionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformCollectionCell.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1742B8C933A00BE653E /* TransformViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1752B8C933A00BE653E /* TransformationCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformationCell.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1772B8C933A00BE653E /* RevealImageController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RevealImageController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1782B8C933A00BE653E /* DeliveryTransformCollectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeliveryTransformCollectionController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1792B8C933A00BE653E /* TransformCollectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformCollectionController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED17B2B8C933A00BE653E /* SmartCroppingController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SmartCroppingController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED17D2B8C933A00BE653E /* UseCaseCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UseCaseCell.swift; sourceTree = \"<group>\"; };\n\t\tB64ED17E2B8C933A00BE653E /* UseCaseCollectionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UseCaseCollectionCell.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1802B8C933A00BE653E /* ConditionalProductViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConditionalProductViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1812B8C933A00BE653E /* NormalizingProductAssetsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NormalizingProductAssetsViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1822B8C933A00BE653E /* UseCasesCollectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UseCasesCollectionController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1832B8C933A00BE653E /* DeliveryUseCasesCollectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeliveryUseCasesCollectionController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1842B8C933A00BE653E /* UseCasesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UseCasesViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1852B8C933A00BE653E /* DeliveryViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeliveryViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1872B8C933A00BE653E /* UploadChoiceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadChoiceController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1882B8C933A00BE653E /* InnerUploadFrame.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InnerUploadFrame.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1892B8C933A00BE653E /* SingleUploadViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleUploadViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED18A2B8C933A00BE653E /* UploadViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED18B2B8C933A00BE653E /* UploadNoCloudController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadNoCloudController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED18D2B8C933A00BE653E /* UploadDoesNotExistController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadDoesNotExistController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED18E2B8C933A00BE653E /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1912B8C933A00BE653E /* video_links.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = video_links.plist; sourceTree = \"<group>\"; };\n\t\tB64ED1932B8C933A00BE653E /* VideoSocialOverlaysController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoSocialOverlaysController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1942B8C933A00BE653E /* VideoFeedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoFeedViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1952B8C933A00BE653E /* MainPageController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainPageController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1962B8C933A00BE653E /* VideoFeedContainerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoFeedContainerController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1972B8C933A00BE653E /* VideoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1982B8C933A00BE653E /* VideoFeedController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoFeedController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED19A2B8C933A00BE653E /* VideoHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoHelper.swift; sourceTree = \"<group>\"; };\n\t\tB64ED19B2B8C933A00BE653E /* SplashViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED19D2B8C933A00BE653E /* BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED19F2B8C933A00BE653E /* WidgetsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WidgetsViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1A02B8C933A00BE653E /* ImageWidgetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageWidgetViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1A12B8C933A00BE653E /* UploadWidgetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadWidgetViewController.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1A52B8C933A00BE653E /* Toolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Toolbar.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1A62B8C933A00BE653E /* Toolbar.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Toolbar.xib; sourceTree = \"<group>\"; };\n\t\tB64ED1A82B8C933A00BE653E /* ToolbarItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarItem.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1A92B8C933A00BE653E /* ToolbarItem.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ToolbarItem.xib; sourceTree = \"<group>\"; };\n\t\tB64ED1AA2B8C933A00BE653E /* RevealImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RevealImageView.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1AC2B8C933A00BE653E /* UploadLoadingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadLoadingView.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1AD2B8C933A00BE653E /* UploadLoadingView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = UploadLoadingView.xib; sourceTree = \"<group>\"; };\n\t\tB64ED1AE2B8C933A00BE653E /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientView.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1B22B8C933A00BE653E /* VideoFeed.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = VideoFeed.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1B42B8C933A00BE653E /* VideoSocialOverlays.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = VideoSocialOverlays.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1B52B8C933A00BE653E /* Video.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Video.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1B72B8C933A00BE653E /* Delivery.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Delivery.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1B82B8C933A00BE653E /* Optimization.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Optimization.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1B92B8C933A00BE653E /* UseCases.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UseCases.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1BB2B8C933A00BE653E /* NormalizingProductAssets.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NormalizingProductAssets.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1BC2B8C933A00BE653E /* ConditionalProduct.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ConditionalProduct.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1BE2B8C933A00BE653E /* Base.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Base.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1C02B8C933A00BE653E /* ImageWidget.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ImageWidget.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1C22B8C933A00BE653E /* Widgets.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Widgets.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1C42B8C933A00BE653E /* InnerUploadFrame.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = InnerUploadFrame.xib; sourceTree = \"<group>\"; };\n\t\tB64ED1C52B8C933A00BE653E /* Upload.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Upload.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1C62B8C933A00BE653E /* UploadNoCloud.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UploadNoCloud.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1C82B8C933A00BE653E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1CA2B8C933A00BE653E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1CB2B8C933A00BE653E /* Splash.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Splash.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1CD2B8C933A00BE653E /* SmartCropping.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SmartCropping.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1CE2B8C933A00BE653E /* RevealImage.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = RevealImage.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1CF2B8C933A00BE653E /* Transform.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Transform.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1D12B8C933A00BE653E /* UploadDoesNotExist.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UploadDoesNotExist.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1D22B8C933A00BE653E /* SingleUpload.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SingleUpload.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1D32B8C933A00BE653E /* UploadChoice.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UploadChoice.storyboard; sourceTree = \"<group>\"; };\n\t\tB64ED1D52B8C933A00BE653E /* CloudinaryHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudinaryHelper.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1D62B8C933A00BE653E /* FileUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileUtils.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1D82B8C933B00BE653E /* Double+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"Double+Extension.swift\"; sourceTree = \"<group>\"; };\n\t\tB64ED1D92B8C933B00BE653E /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1DB2B8C933B00BE653E /* ImageHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageHelper.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1DC2B8C933B00BE653E /* AnimationHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationHelper.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1DE2B8C933B00BE653E /* EventsHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventsHandler.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1DF2B8C933B00BE653E /* FirebaseEventsHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirebaseEventsHandler.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1E02B8C933B00BE653E /* EventObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventObject.swift; sourceTree = \"<group>\"; };\n\t\tB64ED1E12B8C933B00BE653E /* EventsProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventsProvider.swift; sourceTree = \"<group>\"; };\n\t\tB64F0DDA2BC6506700B94590 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tB64F0DDC2BC6541000B94590 /* UploadWidget.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UploadWidget.storyboard; sourceTree = \"<group>\"; };\n\t\tB67476142B8CA0D2006ED6C2 /* IntegrateAIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrateAIViewController.swift; sourceTree = \"<group>\"; };\n\t\tB67476162B8CA0EF006ED6C2 /* IntegrateAI.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = IntegrateAI.storyboard; sourceTree = \"<group>\"; };\n\t\tB694AAF22B308C3C00075041 /* VideoEventsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoEventsTests.swift; sourceTree = \"<group>\"; };\n\t\tB694AAF42B308C5A00075041 /* VideoEventsManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoEventsManagerTests.swift; sourceTree = \"<group>\"; };\n\t\tB6AF51622D4A2A430037965A /* NetworkTestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkTestUtils.swift; sourceTree = \"<group>\"; };\n\t\tB6B4C49E2C56152700C9B604 /* VideoPreprocessTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPreprocessTests.swift; sourceTree = \"<group>\"; };\n\t\tB6C2D4872A72741B00AA0039 /* CLDVideoPlayerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVideoPlayerTests.swift; sourceTree = \"<group>\"; };\n\t\tB6F11F3C288FC20900A895CD /* CLDAnalyticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDAnalyticsTests.swift; sourceTree = \"<group>\"; };\n\t\tB6FFA5C42D4B86020002EFA5 /* Cloudinary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cloudinary.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tD07C87FEDB1F561D123D6873 /* Pods_Cloudinary_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Cloudinary_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tD7119CE2246C7C8100F6B3ED /* CLDConditionExpressionHelpersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDConditionExpressionHelpersTests.swift; sourceTree = \"<group>\"; };\n\t\tD7173495258296CE006F34CD /* Cloudinary_UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Cloudinary_UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tD7173497258296CE006F34CD /* WidgetUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetUITests.swift; sourceTree = \"<group>\"; };\n\t\tD7173499258296CE006F34CD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tD71ADD9B247D976500235AD4 /* CryptoUtilsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CryptoUtilsTests.m; sourceTree = \"<group>\"; };\n\t\tD71B78FD24680743004AA28E /* CLDTransformationVariablesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTransformationVariablesTests.swift; sourceTree = \"<group>\"; };\n\t\tD71B78FF24680773004AA28E /* CLDTransformationExpressionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTransformationExpressionsTests.swift; sourceTree = \"<group>\"; };\n\t\tD71B7901246808EE004AA28E /* CLDTransformationConditionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTransformationConditionsTests.swift; sourceTree = \"<group>\"; };\n\t\tD7289C7E258A9CB5004DBD29 /* dog2.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = dog2.mp4; sourceTree = \"<group>\"; };\n\t\tD7289C80258A9D0B004DBD29 /* UploaderWidgetAssetContainerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetAssetContainerTests.swift; sourceTree = \"<group>\"; };\n\t\tD7289C83258A9E18004DBD29 /* UploaderWidgetVideoControlsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetVideoControlsTests.swift; sourceTree = \"<group>\"; };\n\t\tD7289C84258A9E18004DBD29 /* UploaderWidgetVideoPlayerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetVideoPlayerTests.swift; sourceTree = \"<group>\"; };\n\t\tD7289C85258A9E18004DBD29 /* UploaderWidgetVideoDisplayLinkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetVideoDisplayLinkTests.swift; sourceTree = \"<group>\"; };\n\t\tD7289C86258A9E18004DBD29 /* UploaderWidgetVideoViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetVideoViewTests.swift; sourceTree = \"<group>\"; };\n\t\tD73117572473D7A30051AAFC /* CLDExpressionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CLDExpressionTests.m; sourceTree = \"<group>\"; };\n\t\tD7311759247415340051AAFC /* CLDConditionExpressionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CLDConditionExpressionTests.m; sourceTree = \"<group>\"; };\n\t\tD731175B24741FBE0051AAFC /* CLDTransformationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CLDTransformationTests.m; sourceTree = \"<group>\"; };\n\t\tD7519FAA25E2693A006839B1 /* CLDCloudinaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CLDCloudinaryTests.swift; sourceTree = \"<group>\"; };\n\t\tD7519FAB25E2693A006839B1 /* CLDCloudinaryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CLDCloudinaryTests.m; sourceTree = \"<group>\"; };\n\t\tD7519FEB25E26BE9006839B1 /* DownloaderAssetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloaderAssetTests.swift; sourceTree = \"<group>\"; };\n\t\tD7567063255D661F005B65D3 /* UploaderWidgetViewControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetViewControllerTests.swift; sourceTree = \"<group>\"; };\n\t\tD7788A3724DC482C00B63EB7 /* borderCollieCropped.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = borderCollieCropped.jpg; sourceTree = \"<group>\"; };\n\t\tD7788A9224E29BEC00B63EB7 /* borderCollieRotatedJpg.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = borderCollieRotatedJpg.jpg; sourceTree = \"<group>\"; };\n\t\tD7788A9324E29BEC00B63EB7 /* borderCollieRotatedPng.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = borderCollieRotatedPng.png; sourceTree = \"<group>\"; };\n\t\tD779B69424B7117200E496EB /* UploaderAccessibilityTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderAccessibilityTests.swift; sourceTree = \"<group>\"; };\n\t\tD779B69524B7117200E496EB /* UploaderAccessibilityTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UploaderAccessibilityTests.m; sourceTree = \"<group>\"; };\n\t\tD7866140248FE34A0099DE8C /* textImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = textImage.jpg; sourceTree = \"<group>\"; };\n\t\tD79AE384244CC1D7004F2439 /* CLDTransformationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDTransformationTests.swift; sourceTree = \"<group>\"; };\n\t\tD79AE386244DF1E7004F2439 /* CLDVariableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLDVariableTests.swift; sourceTree = \"<group>\"; };\n\t\tD79AE39B24585533004F2439 /* CLDVariableTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CLDVariableTests.m; sourceTree = \"<group>\"; };\n\t\tD7E79DC324B515260082288A /* UploaderOcrTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderOcrTests.swift; sourceTree = \"<group>\"; };\n\t\tD7E79DC424B515260082288A /* OcrMockProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OcrMockProvider.swift; sourceTree = \"<group>\"; };\n\t\tD7E79DC524B515260082288A /* ExplicitMockOcrTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExplicitMockOcrTests.m; sourceTree = \"<group>\"; };\n\t\tD7E79DC624B515260082288A /* UploaderMockOcrTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UploaderMockOcrTests.m; sourceTree = \"<group>\"; };\n\t\tD7E79DC724B515260082288A /* UploaderMockOcrTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderMockOcrTests.swift; sourceTree = \"<group>\"; };\n\t\tD7E79DC824B515260082288A /* ExplicitMockOcrTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExplicitMockOcrTests.swift; sourceTree = \"<group>\"; };\n\t\tD7E79DD024B515650082288A /* UploadRequestParamsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploadRequestParamsTests.swift; sourceTree = \"<group>\"; };\n\t\tD7EC161E2592261200DD7611 /* borderCollieRotatedJpgUnderIOS12.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = borderCollieRotatedJpgUnderIOS12.jpg; sourceTree = \"<group>\"; };\n\t\tD7EC162025922BA200DD7611 /* borderCollieRotatedPngUnderIOS12.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = borderCollieRotatedPngUnderIOS12.png; sourceTree = \"<group>\"; };\n\t\tD7EF05A8255D8B8E00F93827 /* NetworkBaseTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkBaseTest.swift; sourceTree = \"<group>\"; };\n\t\tD7EF05A9255D8B8E00F93827 /* NetworkBaseTestObjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkBaseTestObjc.h; sourceTree = \"<group>\"; };\n\t\tD7EF05AA255D8B8E00F93827 /* NetworkBaseTestObjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetworkBaseTestObjc.m; sourceTree = \"<group>\"; };\n\t\tD7EF05AE255D8C1900F93827 /* UploaderWidgetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetTests.swift; sourceTree = \"<group>\"; };\n\t\tD7EF05AF255D8C1900F93827 /* UploaderWidgetTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UploaderWidgetTests.m; sourceTree = \"<group>\"; };\n\t\tD7F34F2E2504F48C00C282B1 /* UploaderWidgetCollectionCellTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetCollectionCellTests.swift; sourceTree = \"<group>\"; };\n\t\tD7F34F3025052FBD00C282B1 /* UploaderWidgetPreviewViewControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetPreviewViewControllerTests.swift; sourceTree = \"<group>\"; };\n\t\tD7F34F3225052FE700C282B1 /* WidgetBaseTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WidgetBaseTest.swift; sourceTree = \"<group>\"; };\n\t\tD7F34F9025120E0C00C282B1 /* UploaderWidgetEditViewControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UploaderWidgetEditViewControllerTests.swift; sourceTree = \"<group>\"; };\n\t\tD7F3D45F24DC3BAB002C1D27 /* PreprocessUploaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreprocessUploaderTests.swift; sourceTree = \"<group>\"; };\n\t\tDE971235B5CF94F0DA4D461B /* Pods-Cloudinary_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Cloudinary_Example.debug.xcconfig\"; path = \"Target Support Files/Pods-Cloudinary_Example/Pods-Cloudinary_Example.debug.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tE5BA1162DEC8D6E579692502 /* Pods-Cloudinary_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Cloudinary_Example.release.xcconfig\"; path = \"Target Support Files/Pods-Cloudinary_Example/Pods-Cloudinary_Example.release.xcconfig\"; sourceTree = \"<group>\"; };\n\t\tF2530AD793711AEF6C37A33F /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = \"<group>\"; };\n\t\tFB8B4986C00FEC3B8BD40223 /* Pods-Cloudinary_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = \"Pods-Cloudinary_Tests.release.xcconfig\"; path = \"Target Support Files/Pods-Cloudinary_Tests/Pods-Cloudinary_Tests.release.xcconfig\"; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t607FACCD1AFB9204008FA782 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t9753E077581D46FC1463D265 /* Pods_Cloudinary_Example.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t607FACE21AFB9204008FA782 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t5B1EF16C5EA94AD09F6C22C2 /* Pods_Cloudinary_Tests.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tD7173492258296CE006F34CD /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t0293C6AFE5E20FD5F3D8E4D4 /* Pods */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tDE971235B5CF94F0DA4D461B /* Pods-Cloudinary_Example.debug.xcconfig */,\n\t\t\t\tE5BA1162DEC8D6E579692502 /* Pods-Cloudinary_Example.release.xcconfig */,\n\t\t\t\t2F5D96AD5982EFEBDEE91350 /* Pods-Cloudinary_Tests.debug.xcconfig */,\n\t\t\t\tFB8B4986C00FEC3B8BD40223 /* Pods-Cloudinary_Tests.release.xcconfig */,\n\t\t\t);\n\t\t\tpath = Pods;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t1E635A6E25A757DA0003E9D3 /* MockProvider */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1E635A6F25A757DA0003E9D3 /* BaseMockProvider.swift */,\n\t\t\t);\n\t\t\tpath = MockProvider;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t1E635A7725A7585E0003E9D3 /* QualityAnalysisUploaderTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1E635A7825A7585E0003E9D3 /* MockProviderQualityAnalysis.swift */,\n\t\t\t\t1E635A7925A7585E0003E9D3 /* ObjcUploaderQualityAnalysisTests.m */,\n\t\t\t\t1E635A7A25A7585E0003E9D3 /* QualityAnalysisUploadResultParserTests.swift */,\n\t\t\t\t1E635A7B25A7585E0003E9D3 /* ObjcQualityAnalysisExplicitResultParserTests.m */,\n\t\t\t\t1E635A7C25A7585E0003E9D3 /* UploaderQualityAnalysisTests.swift */,\n\t\t\t\t1E635A7D25A7585E0003E9D3 /* QualityAnalysisExplicitResultParserTests.swift */,\n\t\t\t\t1E635A7E25A7585E0003E9D3 /* ObjcQualityAnalysisUploadResultParserTests.m */,\n\t\t\t);\n\t\t\tpath = QualityAnalysisUploaderTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t272C513B242B6B6E0093AB1B /* BaseNetwork */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1E635A3C25A756860003E9D3 /* ObjcBaseTestCase.h */,\n\t\t\t\t1E635A3D25A756860003E9D3 /* ObjcBaseTestCase.m */,\n\t\t\t\t272C514B242B6C350093AB1B /* BaseTestCase.swift */,\n\t\t\t\t272C51B6242C7F3D0093AB1B /* Core */,\n\t\t\t\t272C51B7242C80720093AB1B /* Extensions */,\n\t\t\t\t272C51B8242C80E70093AB1B /* Features */,\n\t\t\t\t272C514C242B6C350093AB1B /* Resources */,\n\t\t\t);\n\t\t\tpath = BaseNetwork;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t272C514C242B6C350093AB1B /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t272C514D242B6C350093AB1B /* Images */,\n\t\t\t\t272C5150242B6C350093AB1B /* Responses */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t272C514D242B6C350093AB1B /* Images */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t272C514E242B6C350093AB1B /* unicorn.png */,\n\t\t\t\t272C514F242B6C350093AB1B /* rainbow.jpg */,\n\t\t\t);\n\t\t\tpath = Images;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t272C5150242B6C350093AB1B /* Responses */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t272C5151242B6C350093AB1B /* Property List */,\n\t\t\t\t272C5155242B6C350093AB1B /* JSON */,\n\t\t\t\t272C5159242B6C350093AB1B /* String */,\n\t\t\t);\n\t\t\tpath = Responses;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t272C5151242B6C350093AB1B /* Property List */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t272C5152242B6C350093AB1B /* invalid.data */,\n\t\t\t\t272C5153242B6C350093AB1B /* valid.data */,\n\t\t\t\t272C5154242B6C350093AB1B /* empty.data */,\n\t\t\t);\n\t\t\tpath = \"Property List\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t272C5155242B6C350093AB1B /* JSON */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t272C5156242B6C350093AB1B /* empty_data.json */,\n\t\t\t\t272C5157242B6C350093AB1B /* valid_data.json */,\n\t\t\t\t272C5158242B6C350093AB1B /* invalid_data.json */,\n\t\t\t);\n\t\t\tpath = JSON;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t272C5159242B6C350093AB1B /* String */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t272C515A242B6C350093AB1B /* utf8_string.txt */,\n\t\t\t\t272C515B242B6C350093AB1B /* utf32_string.txt */,\n\t\t\t\t272C515C242B6C350093AB1B /* empty_string.txt */,\n\t\t\t);\n\t\t\tpath = String;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t272C51B6242C7F3D0093AB1B /* Core */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7519FAB25E2693A006839B1 /* CLDCloudinaryTests.m */,\n\t\t\t\tD7519FAA25E2693A006839B1 /* CLDCloudinaryTests.swift */,\n\t\t\t\t272C5140242B6C340093AB1B /* AuthenticationTests.swift */,\n\t\t\t\t272C517E242B6C360093AB1B /* ParameterEncodingTests.swift */,\n\t\t\t\t272C5141242B6C350093AB1B /* RequestTests.swift */,\n\t\t\t\t272C5148242B6C350093AB1B /* ResponseTests.swift */,\n\t\t\t\t272C517D242B6C360093AB1B /* ResultTests.swift */,\n\t\t\t\t272C5142242B6C350093AB1B /* SessionDelegateTests.swift */,\n\t\t\t\t272C513E242B6C340093AB1B /* SessionManagerTests.swift */,\n\t\t\t\t272C5179242B6C360093AB1B /* UploadTests.swift */,\n\t\t\t);\n\t\t\tpath = Core;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t272C51B7242C80720093AB1B /* Extensions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t272C517C242B6C360093AB1B /* CLDNError+CloudinaryTests.swift */,\n\t\t\t\t272C513F242B6C340093AB1B /* FileManager+CloudinaryTests.swift */,\n\t\t\t\t27BC1FAD2431C3F6000AFC2C /* CLDNDataResponse+CloudinaryTests.swift */,\n\t\t\t\t27BC1FAF2431C48D000AFC2C /* CLDNResult+CloudinaryTests.swift */,\n\t\t\t);\n\t\t\tpath = Extensions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t272C51B8242C80E70093AB1B /* Features */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD751A01225E26D5D006839B1 /* CLDURLCacheTests */,\n\t\t\t\t272C517A242B6C360093AB1B /* CacheTests.swift */,\n\t\t\t\t272C5145242B6C350093AB1B /* MultipartFormDataTests.swift */,\n\t\t\t\t272C5144242B6C350093AB1B /* ResponseSerializationTests.swift */,\n\t\t\t\t272C5146242B6C350093AB1B /* URLProtocolTests.swift */,\n\t\t\t\t272C514A242B6C350093AB1B /* ValidationTests.swift */,\n\t\t\t);\n\t\t\tpath = Features;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t274C6D1623FBAF5E0090BC40 /* GenerateUrlTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t274C6D1723FBAF5E0090BC40 /* UrlTests.m */,\n\t\t\t\t274C6D1823FBAF5E0090BC40 /* UrlTests.swift */,\n\t\t\t);\n\t\t\tpath = GenerateUrlTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t274C6D1923FBAF5E0090BC40 /* UIExtensions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB694AAF62B308C6B00075041 /* Video Analytics */,\n\t\t\t\t274C6D1A23FBAF5E0090BC40 /* UIBaseTest.swift */,\n\t\t\t\t274C6D1B23FBAF5E0090BC40 /* UIButtonTests.swift */,\n\t\t\t\t274C6D1C23FBAF5E0090BC40 /* UIImageViewTests.swift */,\n\t\t\t\tB6C2D4872A72741B00AA0039 /* CLDVideoPlayerTests.swift */,\n\t\t\t);\n\t\t\tpath = UIExtensions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t274C6D1D23FBAF5E0090BC40 /* NetworkTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD73622B724910FDD0021E1D4 /* UploaderTests */,\n\t\t\t\tD7EF05A7255D8B6D00F93827 /* NetworkBaseTests */,\n\t\t\t\tD779B69324B7117200E496EB /* AccessibilityUploderTests */,\n\t\t\t\t274C6D2023FBAF5E0090BC40 /* ManagementApiTests.swift */,\n\t\t\t\t274C6D2123FBAF5E0090BC40 /* DownloaderTests.swift */,\n\t\t\t\tD7519FEB25E26BE9006839B1 /* DownloaderAssetTests.swift */,\n\t\t\t\tB6AF51622D4A2A430037965A /* NetworkTestUtils.swift */,\n\t\t\t);\n\t\t\tpath = NetworkTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t274C6D2323FBAF5E0090BC40 /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t274C6D2423FBAF5E0090BC40 /* Images */,\n\t\t\t\t274C6D2723FBAF5E0090BC40 /* Docs */,\n\t\t\t\t274C6D2A23FBAF5E0090BC40 /* Videos */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t274C6D2423FBAF5E0090BC40 /* Images */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7EC161E2592261200DD7611 /* borderCollieRotatedJpgUnderIOS12.jpg */,\n\t\t\t\tD7788A9224E29BEC00B63EB7 /* borderCollieRotatedJpg.jpg */,\n\t\t\t\tD7788A9324E29BEC00B63EB7 /* borderCollieRotatedPng.png */,\n\t\t\t\tD7EC162025922BA200DD7611 /* borderCollieRotatedPngUnderIOS12.png */,\n\t\t\t\t274C6D2523FBAF5E0090BC40 /* borderCollie.jpg */,\n\t\t\t\tD7788A3724DC482C00B63EB7 /* borderCollieCropped.jpg */,\n\t\t\t\tD7866140248FE34A0099DE8C /* textImage.jpg */,\n\t\t\t\t274C6D2623FBAF5E0090BC40 /* logo.png */,\n\t\t\t);\n\t\t\tpath = Images;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t274C6D2723FBAF5E0090BC40 /* Docs */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t274C6D2823FBAF5E0090BC40 /* docx.docx */,\n\t\t\t\t274C6D2923FBAF5E0090BC40 /* pdf.pdf */,\n\t\t\t);\n\t\t\tpath = Docs;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t274C6D2A23FBAF5E0090BC40 /* Videos */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7289C7E258A9CB5004DBD29 /* dog2.mp4 */,\n\t\t\t\t274C6D2B23FBAF5E0090BC40 /* dog.mov */,\n\t\t\t\t274C6D2C23FBAF5E0090BC40 /* dog.mp4 */,\n\t\t\t);\n\t\t\tpath = Videos;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t2752795D245ED68F00908341 /* CLDExpressionTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD73117572473D7A30051AAFC /* CLDExpressionTests.m */,\n\t\t\t\t5D7C2DCE245E93F7007E95F7 /* CLDExpressionTests.swift */,\n\t\t\t);\n\t\t\tpath = CLDExpressionTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t29B7FB6ECAB68FF54197832A /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB60F3C232D4B86E200160FFC /* Cloudinary.framework */,\n\t\t\t\tB6FFA5C42D4B86020002EFA5 /* Cloudinary.framework */,\n\t\t\t\t7EAA36BF6CA4E5748DFCD320 /* Pods_Cloudinary_Example.framework */,\n\t\t\t\tD07C87FEDB1F561D123D6873 /* Pods_Cloudinary_Tests.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5D4D8C2A246098A200AE9C96 /* CLDConditionExpressionTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5D4D8C2B246098BA00AE9C96 /* CLDConditionExpressionTests.swift */,\n\t\t\t\tD7119CE2246C7C8100F6B3ED /* CLDConditionExpressionHelpersTests.swift */,\n\t\t\t\tD7311759247415340051AAFC /* CLDConditionExpressionTests.m */,\n\t\t\t);\n\t\t\tpath = CLDConditionExpressionTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5D53A94E2488CDB7005C14AB /* ConfigurationTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5D53A9502488CE23005C14AB /* CLDConfigurationTests.m */,\n\t\t\t\t5D53A94F2488CE23005C14AB /* CLDConfigurationTests.swift */,\n\t\t\t\tB6F11F3C288FC20900A895CD /* CLDAnalyticsTests.swift */,\n\t\t\t);\n\t\t\tpath = ConfigurationTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5DB2D29424FFE2E600001845 /* UploadWidgetTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7EF05AD255D8C0000F93827 /* UploaderWidgetTests */,\n\t\t\t\tD7178DA8255D6578007C1995 /* UploaderWidgetViewControllerTests */,\n\t\t\t\tD7F34F2D2504F46600C282B1 /* UploaderWidgetPreviewTests */,\n\t\t\t\tD7F34F8F25120DE400C282B1 /* UploaderWidgetEditTests */,\n\t\t\t\tD7289C82258A9DD4004DBD29 /* UploadWidgetVideoTests */,\n\t\t\t\t5DB2D29524FFE31000001845 /* UploadWidgetHelpersTests */,\n\t\t\t\tD7F34F3225052FE700C282B1 /* WidgetBaseTest.swift */,\n\t\t\t);\n\t\t\tpath = UploadWidgetTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5DB2D29524FFE31000001845 /* UploadWidgetHelpersTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5DB2D29724FFE32500001845 /* UploaderWidgetConfigurationTests.m */,\n\t\t\t\t5DB2D29624FFE32500001845 /* UploaderWidgetConfigurationTests.swift */,\n\t\t\t\tD7289C80258A9D0B004DBD29 /* UploaderWidgetAssetContainerTests.swift */,\n\t\t\t);\n\t\t\tpath = UploadWidgetHelpersTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t5DBC4D49247BFE570014B37E /* TransformationTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5D4D8C2A246098A200AE9C96 /* CLDConditionExpressionTests */,\n\t\t\t\t2752795D245ED68F00908341 /* CLDExpressionTests */,\n\t\t\t\tD79AE39A245854A6004F2439 /* CLDTransformationTests */,\n\t\t\t\tD79AE39924585499004F2439 /* CLDVariableTests */,\n\t\t\t);\n\t\t\tpath = TransformationTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t607FACC71AFB9204008FA782 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t607FACF51AFB993E008FA782 /* Podspec Metadata */,\n\t\t\t\t607FACD21AFB9204008FA782 /* Example for Cloudinary */,\n\t\t\t\t607FACE81AFB9204008FA782 /* Tests */,\n\t\t\t\tD7173496258296CE006F34CD /* WidgetUITests */,\n\t\t\t\t607FACD11AFB9204008FA782 /* Products */,\n\t\t\t\t0293C6AFE5E20FD5F3D8E4D4 /* Pods */,\n\t\t\t\t29B7FB6ECAB68FF54197832A /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t607FACD11AFB9204008FA782 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t607FACD01AFB9204008FA782 /* Cloudinary_Example.app */,\n\t\t\t\t607FACE51AFB9204008FA782 /* Cloudinary_Tests.xctest */,\n\t\t\t\tD7173495258296CE006F34CD /* Cloudinary_UITests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t607FACD21AFB9204008FA782 /* Example for Cloudinary */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64120C22C48EE5F005A5495 /* Core Data */,\n\t\t\t\tB64ED1632B8C933900BE653E /* AppDelegate.swift */,\n\t\t\t\tB64ED1682B8C933A00BE653E /* Assets.xcassets */,\n\t\t\t\tB64ED1672B8C933A00BE653E /* Colors.xcassets */,\n\t\t\t\tB64ED1692B8C933A00BE653E /* Controllers */,\n\t\t\t\tB64ED1A32B8C933A00BE653E /* Custom Views */,\n\t\t\t\tB64ED1D72B8C933B00BE653E /* Extensions */,\n\t\t\t\tB64ED1642B8C933900BE653E /* GoogleService-Info.plist */,\n\t\t\t\tB64ED1DA2B8C933B00BE653E /* Helpers */,\n\t\t\t\tB64F0DDA2BC6506700B94590 /* Info.plist */,\n\t\t\t\tB64ED1D92B8C933B00BE653E /* SceneDelegate.swift */,\n\t\t\t\tB64ED1D42B8C933A00BE653E /* Utils */,\n\t\t\t\tB64ED1AF2B8C933A00BE653E /* Views */,\n\t\t\t\tB64ED1622B8C933900BE653E /* Cloudinary_Example-Bridging-Header.h */,\n\t\t\t);\n\t\t\tname = \"Example for Cloudinary\";\n\t\t\tpath = Cloudinary;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t607FACE81AFB9204008FA782 /* Tests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB6B4C49D2C56151100C9B604 /* Preprocess */,\n\t\t\t\t272C513B242B6B6E0093AB1B /* BaseNetwork */,\n\t\t\t\tD7E79DCF24B515650082288A /* ParamTests */,\n\t\t\t\tD71ADD9A247D973E00235AD4 /* CryptoUtilsTests */,\n\t\t\t\t274C6D1523FBAF5E0090BC40 /* FileUtilsTests.swift */,\n\t\t\t\t274C6D1623FBAF5E0090BC40 /* GenerateUrlTests */,\n\t\t\t\t274C6D1D23FBAF5E0090BC40 /* NetworkTests */,\n\t\t\t\t5DBC4D49247BFE570014B37E /* TransformationTests */,\n\t\t\t\t5D53A94E2488CDB7005C14AB /* ConfigurationTests */,\n\t\t\t\t274C6D2323FBAF5E0090BC40 /* Resources */,\n\t\t\t\t274C6D2223FBAF5E0090BC40 /* StringUtilsTest.swift */,\n\t\t\t\t274C6D1923FBAF5E0090BC40 /* UIExtensions */,\n\t\t\t\t5DB2D29424FFE2E600001845 /* UploadWidgetTests */,\n\t\t\t\t607FACE91AFB9204008FA782 /* Supporting Files */,\n\t\t\t\tB60F3C212D4B86AF00160FFC /* TestableCloudinary.swift */,\n\t\t\t);\n\t\t\tpath = Tests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t607FACE91AFB9204008FA782 /* Supporting Files */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t607FACEA1AFB9204008FA782 /* Info.plist */,\n\t\t\t);\n\t\t\tname = \"Supporting Files\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t607FACF51AFB993E008FA782 /* Podspec Metadata */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tAA2F53C389142220209152BA /* Cloudinary.podspec */,\n\t\t\t\tF2530AD793711AEF6C37A33F /* README.md */,\n\t\t\t\t270C1BF623FBBA3C00A503C3 /* LICENSE */,\n\t\t\t);\n\t\t\tname = \"Podspec Metadata\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64120BB2C48ED2A005A5495 /* Single Upload */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1892B8C933A00BE653E /* SingleUploadViewController.swift */,\n\t\t\t\tB64120BC2C48ED3F005A5495 /* SingleUploadCell.swift */,\n\t\t\t\tB64120BE2C48ED69005A5495 /* SingleUploadCollectionController.swift */,\n\t\t\t\tB64120C02C48ED83005A5495 /* SingleUploadCollectionLayout.swift */,\n\t\t\t\tB64120CE2C48F049005A5495 /* SingleUploadPreview.swift */,\n\t\t\t);\n\t\t\tpath = \"Single Upload\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64120C22C48EE5F005A5495 /* Core Data */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64120C92C48EF10005A5495 /* AssetModel.xcdatamodeld */,\n\t\t\t\tB64120C32C48EE76005A5495 /* AssetItems+CoreDataClass.swift */,\n\t\t\t\tB64120C52C48EEC7005A5495 /* AssetItems+CoreDataProperties.swift */,\n\t\t\t\tB64120C72C48EED7005A5495 /* AssetModel.swift */,\n\t\t\t\tB64120CC2C48EF22005A5495 /* CoreDataHelper.swift */,\n\t\t\t);\n\t\t\tpath = \"Core Data\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1692B8C933A00BE653E /* Controllers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED16A2B8C933A00BE653E /* Inner Views */,\n\t\t\t\tB64ED18E2B8C933A00BE653E /* MainViewController.swift */,\n\t\t\t\tB64ED18F2B8C933A00BE653E /* Video Feed */,\n\t\t\t\tB64ED19B2B8C933A00BE653E /* SplashViewController.swift */,\n\t\t\t\tB64ED19C2B8C933A00BE653E /* Base */,\n\t\t\t\tB64ED19E2B8C933A00BE653E /* Widgets */,\n\t\t\t);\n\t\t\tpath = Controllers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED16A2B8C933A00BE653E /* Inner Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED16B2B8C933A00BE653E /* Video */,\n\t\t\t\tB64ED16F2B8C933A00BE653E /* Transform */,\n\t\t\t\tB64ED1862B8C933A00BE653E /* Upload */,\n\t\t\t);\n\t\t\tpath = \"Inner Views\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED16B2B8C933A00BE653E /* Video */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED16C2B8C933A00BE653E /* VideoFeedCollectionController.swift */,\n\t\t\t\tB64ED16D2B8C933A00BE653E /* Video Feed */,\n\t\t\t);\n\t\t\tpath = Video;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED16D2B8C933A00BE653E /* Video Feed */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED16E2B8C933A00BE653E /* VideoFeedCell.swift */,\n\t\t\t);\n\t\t\tpath = \"Video Feed\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED16F2B8C933A00BE653E /* Transform */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1702B8C933A00BE653E /* Optimization */,\n\t\t\t\tB64ED1722B8C933A00BE653E /* Transformation */,\n\t\t\t\tB64ED17C2B8C933A00BE653E /* Use Cases */,\n\t\t\t\tB64ED1852B8C933A00BE653E /* DeliveryViewController.swift */,\n\t\t\t);\n\t\t\tpath = Transform;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1702B8C933A00BE653E /* Optimization */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1712B8C933A00BE653E /* OptimizationViewController.swift */,\n\t\t\t);\n\t\t\tpath = Optimization;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1722B8C933A00BE653E /* Transformation */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1732B8C933A00BE653E /* TransformCollectionCell.swift */,\n\t\t\t\tB64ED1742B8C933A00BE653E /* TransformViewController.swift */,\n\t\t\t\tB64ED1752B8C933A00BE653E /* TransformationCell.swift */,\n\t\t\t\tB64ED1762B8C933A00BE653E /* Reveal Image */,\n\t\t\t\tB64ED1782B8C933A00BE653E /* DeliveryTransformCollectionController.swift */,\n\t\t\t\tB64ED1792B8C933A00BE653E /* TransformCollectionController.swift */,\n\t\t\t\tB64ED17A2B8C933A00BE653E /* Smart Cropping */,\n\t\t\t);\n\t\t\tpath = Transformation;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1762B8C933A00BE653E /* Reveal Image */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1772B8C933A00BE653E /* RevealImageController.swift */,\n\t\t\t);\n\t\t\tpath = \"Reveal Image\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED17A2B8C933A00BE653E /* Smart Cropping */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED17B2B8C933A00BE653E /* SmartCroppingController.swift */,\n\t\t\t);\n\t\t\tpath = \"Smart Cropping\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED17C2B8C933A00BE653E /* Use Cases */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED17D2B8C933A00BE653E /* UseCaseCell.swift */,\n\t\t\t\tB64ED17E2B8C933A00BE653E /* UseCaseCollectionCell.swift */,\n\t\t\t\tB64ED17F2B8C933A00BE653E /* Screens */,\n\t\t\t\tB64ED1822B8C933A00BE653E /* UseCasesCollectionController.swift */,\n\t\t\t\tB64ED1832B8C933A00BE653E /* DeliveryUseCasesCollectionController.swift */,\n\t\t\t\tB64ED1842B8C933A00BE653E /* UseCasesViewController.swift */,\n\t\t\t);\n\t\t\tpath = \"Use Cases\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED17F2B8C933A00BE653E /* Screens */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1802B8C933A00BE653E /* ConditionalProductViewController.swift */,\n\t\t\t\tB64ED1812B8C933A00BE653E /* NormalizingProductAssetsViewController.swift */,\n\t\t\t\tB67476142B8CA0D2006ED6C2 /* IntegrateAIViewController.swift */,\n\t\t\t);\n\t\t\tpath = Screens;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1862B8C933A00BE653E /* Upload */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64120BB2C48ED2A005A5495 /* Single Upload */,\n\t\t\t\tB64ED1872B8C933A00BE653E /* UploadChoiceController.swift */,\n\t\t\t\tB64ED1882B8C933A00BE653E /* InnerUploadFrame.swift */,\n\t\t\t\tB64ED18A2B8C933A00BE653E /* UploadViewController.swift */,\n\t\t\t\tB64ED18B2B8C933A00BE653E /* UploadNoCloudController.swift */,\n\t\t\t\tB64ED18C2B8C933A00BE653E /* Upload Does Not Exist */,\n\t\t\t);\n\t\t\tpath = Upload;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED18C2B8C933A00BE653E /* Upload Does Not Exist */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED18D2B8C933A00BE653E /* UploadDoesNotExistController.swift */,\n\t\t\t);\n\t\t\tpath = \"Upload Does Not Exist\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED18F2B8C933A00BE653E /* Video Feed */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1902B8C933A00BE653E /* Resources */,\n\t\t\t\tB64ED1922B8C933A00BE653E /* Controllers */,\n\t\t\t\tB64ED1992B8C933A00BE653E /* Helpers */,\n\t\t\t);\n\t\t\tpath = \"Video Feed\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1902B8C933A00BE653E /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1912B8C933A00BE653E /* video_links.plist */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1922B8C933A00BE653E /* Controllers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1932B8C933A00BE653E /* VideoSocialOverlaysController.swift */,\n\t\t\t\tB64ED1942B8C933A00BE653E /* VideoFeedViewController.swift */,\n\t\t\t\tB64ED1952B8C933A00BE653E /* MainPageController.swift */,\n\t\t\t\tB64ED1962B8C933A00BE653E /* VideoFeedContainerController.swift */,\n\t\t\t\tB64ED1972B8C933A00BE653E /* VideoViewController.swift */,\n\t\t\t\tB64ED1982B8C933A00BE653E /* VideoFeedController.swift */,\n\t\t\t);\n\t\t\tpath = Controllers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1992B8C933A00BE653E /* Helpers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED19A2B8C933A00BE653E /* VideoHelper.swift */,\n\t\t\t);\n\t\t\tpath = Helpers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED19C2B8C933A00BE653E /* Base */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED19D2B8C933A00BE653E /* BaseViewController.swift */,\n\t\t\t);\n\t\t\tpath = Base;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED19E2B8C933A00BE653E /* Widgets */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED19F2B8C933A00BE653E /* WidgetsViewController.swift */,\n\t\t\t\tB64ED1A02B8C933A00BE653E /* ImageWidgetViewController.swift */,\n\t\t\t\tB64ED1A12B8C933A00BE653E /* UploadWidgetViewController.swift */,\n\t\t\t);\n\t\t\tpath = Widgets;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1A32B8C933A00BE653E /* Custom Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1A42B8C933A00BE653E /* ToolBar */,\n\t\t\t\tB64ED1AA2B8C933A00BE653E /* RevealImageView.swift */,\n\t\t\t\tB64ED1AB2B8C933A00BE653E /* Upload Loading View */,\n\t\t\t\tB64ED1AE2B8C933A00BE653E /* GradientView.swift */,\n\t\t\t);\n\t\t\tpath = \"Custom Views\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1A42B8C933A00BE653E /* ToolBar */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1A52B8C933A00BE653E /* Toolbar.swift */,\n\t\t\t\tB64ED1A62B8C933A00BE653E /* Toolbar.xib */,\n\t\t\t\tB64ED1A72B8C933A00BE653E /* Item */,\n\t\t\t);\n\t\t\tpath = ToolBar;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1A72B8C933A00BE653E /* Item */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1A82B8C933A00BE653E /* ToolbarItem.swift */,\n\t\t\t\tB64ED1A92B8C933A00BE653E /* ToolbarItem.xib */,\n\t\t\t);\n\t\t\tpath = Item;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1AB2B8C933A00BE653E /* Upload Loading View */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1AC2B8C933A00BE653E /* UploadLoadingView.swift */,\n\t\t\t\tB64ED1AD2B8C933A00BE653E /* UploadLoadingView.xib */,\n\t\t\t);\n\t\t\tpath = \"Upload Loading View\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1AF2B8C933A00BE653E /* Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1B02B8C933A00BE653E /* Inner Views */,\n\t\t\t\tB64ED1C72B8C933A00BE653E /* LaunchScreen.storyboard */,\n\t\t\t\tB64ED1C92B8C933A00BE653E /* Main.storyboard */,\n\t\t\t\tB64ED1CB2B8C933A00BE653E /* Splash.storyboard */,\n\t\t\t\tB64ED1CC2B8C933A00BE653E /* Transform */,\n\t\t\t\tB64ED1D02B8C933A00BE653E /* Upload */,\n\t\t\t);\n\t\t\tpath = Views;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1B02B8C933A00BE653E /* Inner Views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1B12B8C933A00BE653E /* Video */,\n\t\t\t\tB64ED1B62B8C933A00BE653E /* Transform */,\n\t\t\t\tB64ED1BD2B8C933A00BE653E /* Base */,\n\t\t\t\tB64ED1BF2B8C933A00BE653E /* Widgets */,\n\t\t\t\tB64ED1C32B8C933A00BE653E /* Upload */,\n\t\t\t);\n\t\t\tpath = \"Inner Views\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1B12B8C933A00BE653E /* Video */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1B22B8C933A00BE653E /* VideoFeed.storyboard */,\n\t\t\t\tB64ED1B32B8C933A00BE653E /* Social */,\n\t\t\t\tB64ED1B52B8C933A00BE653E /* Video.storyboard */,\n\t\t\t);\n\t\t\tpath = Video;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1B32B8C933A00BE653E /* Social */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1B42B8C933A00BE653E /* VideoSocialOverlays.storyboard */,\n\t\t\t);\n\t\t\tpath = Social;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1B62B8C933A00BE653E /* Transform */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1B72B8C933A00BE653E /* Delivery.storyboard */,\n\t\t\t\tB64ED1B82B8C933A00BE653E /* Optimization.storyboard */,\n\t\t\t\tB64ED1B92B8C933A00BE653E /* UseCases.storyboard */,\n\t\t\t\tB64ED1BA2B8C933A00BE653E /* Use Cases */,\n\t\t\t);\n\t\t\tpath = Transform;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1BA2B8C933A00BE653E /* Use Cases */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1BB2B8C933A00BE653E /* NormalizingProductAssets.storyboard */,\n\t\t\t\tB64ED1BC2B8C933A00BE653E /* ConditionalProduct.storyboard */,\n\t\t\t\tB67476162B8CA0EF006ED6C2 /* IntegrateAI.storyboard */,\n\t\t\t);\n\t\t\tpath = \"Use Cases\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1BD2B8C933A00BE653E /* Base */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1BE2B8C933A00BE653E /* Base.storyboard */,\n\t\t\t);\n\t\t\tpath = Base;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1BF2B8C933A00BE653E /* Widgets */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1C02B8C933A00BE653E /* ImageWidget.storyboard */,\n\t\t\t\tB64ED1C22B8C933A00BE653E /* Widgets.storyboard */,\n\t\t\t\tB64F0DDC2BC6541000B94590 /* UploadWidget.storyboard */,\n\t\t\t);\n\t\t\tpath = Widgets;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1C32B8C933A00BE653E /* Upload */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1C42B8C933A00BE653E /* InnerUploadFrame.xib */,\n\t\t\t\tB64ED1C52B8C933A00BE653E /* Upload.storyboard */,\n\t\t\t\tB64ED1C62B8C933A00BE653E /* UploadNoCloud.storyboard */,\n\t\t\t);\n\t\t\tpath = Upload;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1CC2B8C933A00BE653E /* Transform */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1CD2B8C933A00BE653E /* SmartCropping.storyboard */,\n\t\t\t\tB64ED1CE2B8C933A00BE653E /* RevealImage.storyboard */,\n\t\t\t\tB64ED1CF2B8C933A00BE653E /* Transform.storyboard */,\n\t\t\t);\n\t\t\tpath = Transform;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1D02B8C933A00BE653E /* Upload */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1D12B8C933A00BE653E /* UploadDoesNotExist.storyboard */,\n\t\t\t\tB64ED1D22B8C933A00BE653E /* SingleUpload.storyboard */,\n\t\t\t\tB64ED1D32B8C933A00BE653E /* UploadChoice.storyboard */,\n\t\t\t\tB64120D02C48F0EC005A5495 /* SingleUploadPreview.storyboard */,\n\t\t\t);\n\t\t\tpath = Upload;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1D42B8C933A00BE653E /* Utils */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1D52B8C933A00BE653E /* CloudinaryHelper.swift */,\n\t\t\t\tB64ED1D62B8C933A00BE653E /* FileUtils.swift */,\n\t\t\t);\n\t\t\tpath = Utils;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1D72B8C933B00BE653E /* Extensions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1D82B8C933B00BE653E /* Double+Extension.swift */,\n\t\t\t);\n\t\t\tpath = Extensions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1DA2B8C933B00BE653E /* Helpers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1DB2B8C933B00BE653E /* ImageHelper.swift */,\n\t\t\t\tB64ED1DC2B8C933B00BE653E /* AnimationHelper.swift */,\n\t\t\t\tB64ED1DD2B8C933B00BE653E /* Events */,\n\t\t\t);\n\t\t\tpath = Helpers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1DD2B8C933B00BE653E /* Events */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1DE2B8C933B00BE653E /* EventsHandler.swift */,\n\t\t\t\tB64ED1DF2B8C933B00BE653E /* FirebaseEventsHandler.swift */,\n\t\t\t\tB64ED1E02B8C933B00BE653E /* EventObject.swift */,\n\t\t\t\tB64ED1E12B8C933B00BE653E /* EventsProvider.swift */,\n\t\t\t);\n\t\t\tpath = Events;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB694AAF62B308C6B00075041 /* Video Analytics */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB694AAF22B308C3C00075041 /* VideoEventsTests.swift */,\n\t\t\t\tB694AAF42B308C5A00075041 /* VideoEventsManagerTests.swift */,\n\t\t\t);\n\t\t\tpath = \"Video Analytics\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB6B4C49D2C56151100C9B604 /* Preprocess */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t274C6D1423FBAF5E0090BC40 /* PreprocessTests.swift */,\n\t\t\t\tB6B4C49E2C56152700C9B604 /* VideoPreprocessTests.swift */,\n\t\t\t);\n\t\t\tpath = Preprocess;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7173496258296CE006F34CD /* WidgetUITests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7173497258296CE006F34CD /* WidgetUITests.swift */,\n\t\t\t\tD7173499258296CE006F34CD /* Info.plist */,\n\t\t\t);\n\t\t\tpath = WidgetUITests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7178DA8255D6578007C1995 /* UploaderWidgetViewControllerTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7567063255D661F005B65D3 /* UploaderWidgetViewControllerTests.swift */,\n\t\t\t);\n\t\t\tpath = UploaderWidgetViewControllerTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD71ADD9A247D973E00235AD4 /* CryptoUtilsTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t274C6D1323FBAF5E0090BC40 /* CryptoUtilsTests.swift */,\n\t\t\t\tD71ADD9B247D976500235AD4 /* CryptoUtilsTests.m */,\n\t\t\t);\n\t\t\tpath = CryptoUtilsTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7289C82258A9DD4004DBD29 /* UploadWidgetVideoTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7289C83258A9E18004DBD29 /* UploaderWidgetVideoControlsTests.swift */,\n\t\t\t\tD7289C85258A9E18004DBD29 /* UploaderWidgetVideoDisplayLinkTests.swift */,\n\t\t\t\tD7289C84258A9E18004DBD29 /* UploaderWidgetVideoPlayerTests.swift */,\n\t\t\t\tD7289C86258A9E18004DBD29 /* UploaderWidgetVideoViewTests.swift */,\n\t\t\t);\n\t\t\tpath = UploadWidgetVideoTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD73622B724910FDD0021E1D4 /* UploaderTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t1E635A7725A7585E0003E9D3 /* QualityAnalysisUploaderTests */,\n\t\t\t\t1E635A6E25A757DA0003E9D3 /* MockProvider */,\n\t\t\t\t274C6D1F23FBAF5E0090BC40 /* UploaderTests.swift */,\n\t\t\t\tD7F3D45E24DC3B8A002C1D27 /* PreprocessUploaderTests */,\n\t\t\t\tD7E79DC224B515260082288A /* OcrUploaderTests */,\n\t\t\t);\n\t\t\tpath = UploaderTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD751A01225E26D5D006839B1 /* CLDURLCacheTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tpath = CLDURLCacheTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD779B69324B7117200E496EB /* AccessibilityUploderTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD779B69424B7117200E496EB /* UploaderAccessibilityTests.swift */,\n\t\t\t\tD779B69524B7117200E496EB /* UploaderAccessibilityTests.m */,\n\t\t\t);\n\t\t\tpath = AccessibilityUploderTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD79AE39924585499004F2439 /* CLDVariableTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD79AE39B24585533004F2439 /* CLDVariableTests.m */,\n\t\t\t\tD79AE386244DF1E7004F2439 /* CLDVariableTests.swift */,\n\t\t\t);\n\t\t\tpath = CLDVariableTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD79AE39A245854A6004F2439 /* CLDTransformationTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t5DE4EC1E2469919700F6C8D6 /* CLDTransformationBaselineTests.swift */,\n\t\t\t\tD79AE384244CC1D7004F2439 /* CLDTransformationTests.swift */,\n\t\t\t\tD71B78FD24680743004AA28E /* CLDTransformationVariablesTests.swift */,\n\t\t\t\tD71B78FF24680773004AA28E /* CLDTransformationExpressionsTests.swift */,\n\t\t\t\tD71B7901246808EE004AA28E /* CLDTransformationConditionsTests.swift */,\n\t\t\t\tD731175B24741FBE0051AAFC /* CLDTransformationTests.m */,\n\t\t\t);\n\t\t\tpath = CLDTransformationTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7E79DC224B515260082288A /* OcrUploaderTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7E79DC324B515260082288A /* UploaderOcrTests.swift */,\n\t\t\t\tD7E79DC424B515260082288A /* OcrMockProvider.swift */,\n\t\t\t\tD7E79DC524B515260082288A /* ExplicitMockOcrTests.m */,\n\t\t\t\tD7E79DC624B515260082288A /* UploaderMockOcrTests.m */,\n\t\t\t\tD7E79DC724B515260082288A /* UploaderMockOcrTests.swift */,\n\t\t\t\tD7E79DC824B515260082288A /* ExplicitMockOcrTests.swift */,\n\t\t\t);\n\t\t\tpath = OcrUploaderTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7E79DCF24B515650082288A /* ParamTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7E79DD024B515650082288A /* UploadRequestParamsTests.swift */,\n\t\t\t);\n\t\t\tpath = ParamTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7EF05A7255D8B6D00F93827 /* NetworkBaseTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7EF05A8255D8B8E00F93827 /* NetworkBaseTest.swift */,\n\t\t\t\tD7EF05A9255D8B8E00F93827 /* NetworkBaseTestObjc.h */,\n\t\t\t\tD7EF05AA255D8B8E00F93827 /* NetworkBaseTestObjc.m */,\n\t\t\t);\n\t\t\tpath = NetworkBaseTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7EF05AD255D8C0000F93827 /* UploaderWidgetTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7EF05AF255D8C1900F93827 /* UploaderWidgetTests.m */,\n\t\t\t\tD7EF05AE255D8C1900F93827 /* UploaderWidgetTests.swift */,\n\t\t\t);\n\t\t\tpath = UploaderWidgetTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7F34F2D2504F46600C282B1 /* UploaderWidgetPreviewTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7F34F2E2504F48C00C282B1 /* UploaderWidgetCollectionCellTests.swift */,\n\t\t\t\tD7F34F3025052FBD00C282B1 /* UploaderWidgetPreviewViewControllerTests.swift */,\n\t\t\t);\n\t\t\tpath = UploaderWidgetPreviewTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7F34F8F25120DE400C282B1 /* UploaderWidgetEditTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7F34F9025120E0C00C282B1 /* UploaderWidgetEditViewControllerTests.swift */,\n\t\t\t);\n\t\t\tpath = UploaderWidgetEditTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tD7F3D45E24DC3B8A002C1D27 /* PreprocessUploaderTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tD7F3D45F24DC3BAB002C1D27 /* PreprocessUploaderTests.swift */,\n\t\t\t);\n\t\t\tpath = PreprocessUploaderTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\t607FACCF1AFB9204008FA782 /* Cloudinary_Example */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget \"Cloudinary_Example\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4DDBDAA6D5EA05A66CEFFB59 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t607FACCC1AFB9204008FA782 /* Sources */,\n\t\t\t\t607FACCD1AFB9204008FA782 /* Frameworks */,\n\t\t\t\t607FACCE1AFB9204008FA782 /* Resources */,\n\t\t\t\t0B0BD5E65F34EDF0AD421887 /* [CP] Embed Pods Frameworks */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = Cloudinary_Example;\n\t\t\tproductName = Cloudinary;\n\t\t\tproductReference = 607FACD01AFB9204008FA782 /* Cloudinary_Example.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t607FACE41AFB9204008FA782 /* Cloudinary_Tests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget \"Cloudinary_Tests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t66267CF881CE925C297775A4 /* [CP] Check Pods Manifest.lock */,\n\t\t\t\t607FACE11AFB9204008FA782 /* Sources */,\n\t\t\t\t607FACE21AFB9204008FA782 /* Frameworks */,\n\t\t\t\t607FACE31AFB9204008FA782 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t607FACE71AFB9204008FA782 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = Cloudinary_Tests;\n\t\t\tproductName = Tests;\n\t\t\tproductReference = 607FACE51AFB9204008FA782 /* Cloudinary_Tests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\tD7173494258296CE006F34CD /* Cloudinary_UITests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = D717349C258296CE006F34CD /* Build configuration list for PBXNativeTarget \"Cloudinary_UITests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tD7173491258296CE006F34CD /* Sources */,\n\t\t\t\tD7173492258296CE006F34CD /* Frameworks */,\n\t\t\t\tD7173493258296CE006F34CD /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tD717349B258296CE006F34CD /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = Cloudinary_UITests;\n\t\t\tproductName = WidgetUITests;\n\t\t\tproductReference = D7173495258296CE006F34CD /* Cloudinary_UITests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.ui-testing\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t607FACC81AFB9204008FA782 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1170;\n\t\t\t\tLastUpgradeCheck = 1250;\n\t\t\t\tORGANIZATIONNAME = CocoaPods;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t607FACCF1AFB9204008FA782 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.3.1;\n\t\t\t\t\t\tDevelopmentTeam = 3TR999VVAS;\n\t\t\t\t\t\tLastSwiftMigration = 1510;\n\t\t\t\t\t};\n\t\t\t\t\t607FACE41AFB9204008FA782 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 6.3.1;\n\t\t\t\t\t\tDevelopmentTeam = 3TR999VVAS;\n\t\t\t\t\t\tLastSwiftMigration = 1130;\n\t\t\t\t\t\tTestTargetID = 607FACCF1AFB9204008FA782;\n\t\t\t\t\t};\n\t\t\t\t\tD7173494258296CE006F34CD = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.7;\n\t\t\t\t\t\tDevelopmentTeam = 69UZJ87W84;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t\tTestTargetID = 607FACCF1AFB9204008FA782;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject \"Cloudinary\" */;\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 = 607FACC71AFB9204008FA782;\n\t\t\tproductRefGroup = 607FACD11AFB9204008FA782 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t607FACCF1AFB9204008FA782 /* Cloudinary_Example */,\n\t\t\t\t607FACE41AFB9204008FA782 /* Cloudinary_Tests */,\n\t\t\t\tD7173494258296CE006F34CD /* Cloudinary_UITests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t607FACCE1AFB9204008FA782 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB64ED21C2B8C933B00BE653E /* NormalizingProductAssets.storyboard in Resources */,\n\t\t\t\tB64ED21E2B8C933B00BE653E /* Base.storyboard in Resources */,\n\t\t\t\tD73DBB0C258BA05A0002E7E5 /* dog.mp4 in Resources */,\n\t\t\t\t270C1BF723FBBA3C00A503C3 /* LICENSE in Resources */,\n\t\t\t\tB64ED21B2B8C933B00BE653E /* UseCases.storyboard in Resources */,\n\t\t\t\tB64ED2292B8C933B00BE653E /* RevealImage.storyboard in Resources */,\n\t\t\t\tB64ED1E32B8C933B00BE653E /* GoogleService-Info.plist in Resources */,\n\t\t\t\tB67476172B8CA0EF006ED6C2 /* IntegrateAI.storyboard in Resources */,\n\t\t\t\tD73DBB0B258BA0570002E7E5 /* dog.mov in Resources */,\n\t\t\t\tB64ED2222B8C933B00BE653E /* InnerUploadFrame.xib in Resources */,\n\t\t\t\tD73DBB0A258BA0550002E7E5 /* dog2.mp4 in Resources */,\n\t\t\t\tB64ED21D2B8C933B00BE653E /* ConditionalProduct.storyboard in Resources */,\n\t\t\t\tB64ED2002B8C933B00BE653E /* video_links.plist in Resources */,\n\t\t\t\tB64ED2192B8C933B00BE653E /* Delivery.storyboard in Resources */,\n\t\t\t\tB64ED22A2B8C933B00BE653E /* Transform.storyboard in Resources */,\n\t\t\t\tB64ED2272B8C933B00BE653E /* Splash.storyboard in Resources */,\n\t\t\t\tB64ED22C2B8C933B00BE653E /* SingleUpload.storyboard in Resources */,\n\t\t\t\tB64ED1E62B8C933B00BE653E /* Assets.xcassets in Resources */,\n\t\t\t\tB64ED2142B8C933B00BE653E /* UploadLoadingView.xib in Resources */,\n\t\t\t\tB64ED20F2B8C933B00BE653E /* Toolbar.xib in Resources */,\n\t\t\t\tB64ED2252B8C933B00BE653E /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tB64ED22B2B8C933B00BE653E /* UploadDoesNotExist.storyboard in Resources */,\n\t\t\t\tB64ED21F2B8C933B00BE653E /* ImageWidget.storyboard in Resources */,\n\t\t\t\tB64120D12C48F0EC005A5495 /* SingleUploadPreview.storyboard in Resources */,\n\t\t\t\tB64ED2112B8C933B00BE653E /* ToolbarItem.xib in Resources */,\n\t\t\t\tB64ED22D2B8C933B00BE653E /* UploadChoice.storyboard in Resources */,\n\t\t\t\tB64ED2262B8C933B00BE653E /* Main.storyboard in Resources */,\n\t\t\t\tB64ED21A2B8C933B00BE653E /* Optimization.storyboard in Resources */,\n\t\t\t\tB64ED2282B8C933B00BE653E /* SmartCropping.storyboard in Resources */,\n\t\t\t\tB64ED2172B8C933B00BE653E /* VideoSocialOverlays.storyboard in Resources */,\n\t\t\t\tB64ED2212B8C933B00BE653E /* Widgets.storyboard in Resources */,\n\t\t\t\tB64ED2162B8C933B00BE653E /* VideoFeed.storyboard in Resources */,\n\t\t\t\tB64F0DDD2BC6541000B94590 /* UploadWidget.storyboard in Resources */,\n\t\t\t\tB64ED2242B8C933B00BE653E /* UploadNoCloud.storyboard in Resources */,\n\t\t\t\tB64ED2182B8C933B00BE653E /* Video.storyboard in Resources */,\n\t\t\t\tB64ED2232B8C933B00BE653E /* Upload.storyboard in Resources */,\n\t\t\t\tB64ED1E52B8C933B00BE653E /* Colors.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t607FACE31AFB9204008FA782 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tD7866141248FE34A0099DE8C /* textImage.jpg in Resources */,\n\t\t\t\t272C5190242B6C360093AB1B /* valid.data in Resources */,\n\t\t\t\t272C5191242B6C360093AB1B /* empty.data in Resources */,\n\t\t\t\t274C6D3F23FBAF5E0090BC40 /* dog.mp4 in Resources */,\n\t\t\t\t274C6D3B23FBAF5E0090BC40 /* logo.png in Resources */,\n\t\t\t\tD7289C7F258A9CB5004DBD29 /* dog2.mp4 in Resources */,\n\t\t\t\t272C5194242B6C360093AB1B /* invalid_data.json in Resources */,\n\t\t\t\tD7788A9424E29BEC00B63EB7 /* borderCollieRotatedJpg.jpg in Resources */,\n\t\t\t\t274C6D3E23FBAF5E0090BC40 /* dog.mov in Resources */,\n\t\t\t\t274C6D3D23FBAF5E0090BC40 /* pdf.pdf in Resources */,\n\t\t\t\t272C518E242B6C360093AB1B /* rainbow.jpg in Resources */,\n\t\t\t\t272C518D242B6C360093AB1B /* unicorn.png in Resources */,\n\t\t\t\t272C5193242B6C360093AB1B /* valid_data.json in Resources */,\n\t\t\t\t272C5195242B6C360093AB1B /* utf8_string.txt in Resources */,\n\t\t\t\t272C5196242B6C360093AB1B /* utf32_string.txt in Resources */,\n\t\t\t\tD7EC162125922BA200DD7611 /* borderCollieRotatedPngUnderIOS12.png in Resources */,\n\t\t\t\t274C6D3C23FBAF5E0090BC40 /* docx.docx in Resources */,\n\t\t\t\t272C5197242B6C360093AB1B /* empty_string.txt in Resources */,\n\t\t\t\t272C518F242B6C360093AB1B /* invalid.data in Resources */,\n\t\t\t\tD7EC161F2592261200DD7611 /* borderCollieRotatedJpgUnderIOS12.jpg in Resources */,\n\t\t\t\tD7788A3824DC482C00B63EB7 /* borderCollieCropped.jpg in Resources */,\n\t\t\t\t274C6D3A23FBAF5E0090BC40 /* borderCollie.jpg in Resources */,\n\t\t\t\t272C5192242B6C360093AB1B /* empty_data.json in Resources */,\n\t\t\t\tD7788A9524E29BEC00B63EB7 /* borderCollieRotatedPng.png in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tD7173493258296CE006F34CD /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t0B0BD5E65F34EDF0AD421887 /* [CP] Embed Pods Frameworks */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_ROOT}/Target Support Files/Pods-Cloudinary_Example/Pods-Cloudinary_Example-frameworks.sh\",\n\t\t\t\t\"${BUILT_PRODUCTS_DIR}/Cloudinary/Cloudinary.framework\",\n\t\t\t);\n\t\t\tname = \"[CP] Embed Pods Frameworks\";\n\t\t\toutputPaths = (\n\t\t\t\t\"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cloudinary.framework\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"\\\"${PODS_ROOT}/Target Support Files/Pods-Cloudinary_Example/Pods-Cloudinary_Example-frameworks.sh\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t4DDBDAA6D5EA05A66CEFFB59 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-Cloudinary_Example-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n\t\t66267CF881CE925C297775A4 /* [CP] Check Pods Manifest.lock */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\",\n\t\t\t\t\"${PODS_ROOT}/Manifest.lock\",\n\t\t\t);\n\t\t\tname = \"[CP] Check Pods Manifest.lock\";\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t\t\"$(DERIVED_FILE_DIR)/Pods-Cloudinary_Tests-checkManifestLockResult.txt\",\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"diff \\\"${PODS_PODFILE_DIR_PATH}/Podfile.lock\\\" \\\"${PODS_ROOT}/Manifest.lock\\\" > /dev/null\\nif [ $? != 0 ] ; then\\n    # print error to STDERR\\n    echo \\\"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\\\" >&2\\n    exit 1\\nfi\\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\\necho \\\"SUCCESS\\\" > \\\"${SCRIPT_OUTPUT_FILE_0}\\\"\\n\";\n\t\t\tshowEnvVarsInLog = 0;\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t607FACCC1AFB9204008FA782 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB64ED1FC2B8C933B00BE653E /* UploadViewController.swift in Sources */,\n\t\t\t\tB64ED1FF2B8C933B00BE653E /* MainViewController.swift in Sources */,\n\t\t\t\tB64ED2032B8C933B00BE653E /* MainPageController.swift in Sources */,\n\t\t\t\tB64ED2082B8C933B00BE653E /* SplashViewController.swift in Sources */,\n\t\t\t\tB64ED2062B8C933B00BE653E /* VideoFeedController.swift in Sources */,\n\t\t\t\tB64ED2342B8C933B00BE653E /* EventsHandler.swift in Sources */,\n\t\t\t\tB64ED2092B8C933B00BE653E /* BaseViewController.swift in Sources */,\n\t\t\t\tB64ED1E22B8C933B00BE653E /* AppDelegate.swift in Sources */,\n\t\t\t\tB64ED1F32B8C933B00BE653E /* ConditionalProductViewController.swift in Sources */,\n\t\t\t\tB64ED2122B8C933B00BE653E /* RevealImageView.swift in Sources */,\n\t\t\t\tB64ED22F2B8C933B00BE653E /* FileUtils.swift in Sources */,\n\t\t\t\tB64ED1F12B8C933B00BE653E /* UseCaseCell.swift in Sources */,\n\t\t\t\tB64ED1F92B8C933B00BE653E /* UploadChoiceController.swift in Sources */,\n\t\t\t\tB64ED2052B8C933B00BE653E /* VideoViewController.swift in Sources */,\n\t\t\t\tB64ED1EA2B8C933B00BE653E /* TransformCollectionCell.swift in Sources */,\n\t\t\t\tB64ED20A2B8C933B00BE653E /* WidgetsViewController.swift in Sources */,\n\t\t\t\tB64ED1EF2B8C933B00BE653E /* TransformCollectionController.swift in Sources */,\n\t\t\t\tB64ED1F02B8C933B00BE653E /* SmartCroppingController.swift in Sources */,\n\t\t\t\tB64ED1F42B8C933B00BE653E /* NormalizingProductAssetsViewController.swift in Sources */,\n\t\t\t\tB64ED2042B8C933B00BE653E /* VideoFeedContainerController.swift in Sources */,\n\t\t\t\tB64ED2012B8C933B00BE653E /* VideoSocialOverlaysController.swift in Sources */,\n\t\t\t\tB64ED1E82B8C933B00BE653E /* VideoFeedCell.swift in Sources */,\n\t\t\t\tB64ED1F82B8C933B00BE653E /* DeliveryViewController.swift in Sources */,\n\t\t\t\tB64ED1FE2B8C933B00BE653E /* UploadDoesNotExistController.swift in Sources */,\n\t\t\t\tB64ED2072B8C933B00BE653E /* VideoHelper.swift in Sources */,\n\t\t\t\tB64ED2362B8C933B00BE653E /* EventObject.swift in Sources */,\n\t\t\t\tB64ED20C2B8C933B00BE653E /* UploadWidgetViewController.swift in Sources */,\n\t\t\t\tB64ED20B2B8C933B00BE653E /* ImageWidgetViewController.swift in Sources */,\n\t\t\t\tB64120CD2C48EF22005A5495 /* CoreDataHelper.swift in Sources */,\n\t\t\t\tB64120C82C48EED7005A5495 /* AssetModel.swift in Sources */,\n\t\t\t\tB64ED1FB2B8C933B00BE653E /* SingleUploadViewController.swift in Sources */,\n\t\t\t\tB64ED2132B8C933B00BE653E /* UploadLoadingView.swift in Sources */,\n\t\t\t\tB64120CB2C48EF10005A5495 /* AssetModel.xcdatamodeld in Sources */,\n\t\t\t\tB64120CF2C48F049005A5495 /* SingleUploadPreview.swift in Sources */,\n\t\t\t\tB64ED1EB2B8C933B00BE653E /* TransformViewController.swift in Sources */,\n\t\t\t\tB64ED2332B8C933B00BE653E /* AnimationHelper.swift in Sources */,\n\t\t\t\tB67476152B8CA0D2006ED6C2 /* IntegrateAIViewController.swift in Sources */,\n\t\t\t\tB64120C42C48EE76005A5495 /* AssetItems+CoreDataClass.swift in Sources */,\n\t\t\t\tB64ED2372B8C933B00BE653E /* EventsProvider.swift in Sources */,\n\t\t\t\tB64ED2352B8C933B00BE653E /* FirebaseEventsHandler.swift in Sources */,\n\t\t\t\tB64ED1FD2B8C933B00BE653E /* UploadNoCloudController.swift in Sources */,\n\t\t\t\tB64ED20E2B8C933B00BE653E /* Toolbar.swift in Sources */,\n\t\t\t\tB64ED1F22B8C933B00BE653E /* UseCaseCollectionCell.swift in Sources */,\n\t\t\t\tB64ED1ED2B8C933B00BE653E /* RevealImageController.swift in Sources */,\n\t\t\t\tB64ED1E92B8C933B00BE653E /* OptimizationViewController.swift in Sources */,\n\t\t\t\tB64120C62C48EEC7005A5495 /* AssetItems+CoreDataProperties.swift in Sources */,\n\t\t\t\tB64120BF2C48ED69005A5495 /* SingleUploadCollectionController.swift in Sources */,\n\t\t\t\tB64120BD2C48ED3F005A5495 /* SingleUploadCell.swift in Sources */,\n\t\t\t\tB64ED1F72B8C933B00BE653E /* UseCasesViewController.swift in Sources */,\n\t\t\t\tB64ED1EC2B8C933B00BE653E /* TransformationCell.swift in Sources */,\n\t\t\t\tB64ED1F52B8C933B00BE653E /* UseCasesCollectionController.swift in Sources */,\n\t\t\t\tB64ED1E72B8C933B00BE653E /* VideoFeedCollectionController.swift in Sources */,\n\t\t\t\tB64ED2302B8C933B00BE653E /* Double+Extension.swift in Sources */,\n\t\t\t\tB64ED2312B8C933B00BE653E /* SceneDelegate.swift in Sources */,\n\t\t\t\tB64ED1EE2B8C933B00BE653E /* DeliveryTransformCollectionController.swift in Sources */,\n\t\t\t\tB64ED1FA2B8C933B00BE653E /* InnerUploadFrame.swift in Sources */,\n\t\t\t\tB64ED22E2B8C933B00BE653E /* CloudinaryHelper.swift in Sources */,\n\t\t\t\tB64ED2022B8C933B00BE653E /* VideoFeedViewController.swift in Sources */,\n\t\t\t\tB64ED2102B8C933B00BE653E /* ToolbarItem.swift in Sources */,\n\t\t\t\tB64ED2152B8C933B00BE653E /* GradientView.swift in Sources */,\n\t\t\t\tB64ED1F62B8C933B00BE653E /* DeliveryUseCasesCollectionController.swift in Sources */,\n\t\t\t\tB64ED2322B8C933B00BE653E /* ImageHelper.swift in Sources */,\n\t\t\t\tB64120C12C48ED83005A5495 /* SingleUploadCollectionLayout.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t607FACE11AFB9204008FA782 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t5DB2D29824FFE32500001845 /* UploaderWidgetConfigurationTests.swift in Sources */,\n\t\t\t\tD7519FAC25E2693A006839B1 /* CLDCloudinaryTests.swift in Sources */,\n\t\t\t\t272C5189242B6C360093AB1B /* ResponseTests.swift in Sources */,\n\t\t\t\tD7519FAD25E2693A006839B1 /* CLDCloudinaryTests.m in Sources */,\n\t\t\t\tD7F3D46024DC3BAB002C1D27 /* PreprocessUploaderTests.swift in Sources */,\n\t\t\t\t1E635A8425A7585E0003E9D3 /* QualityAnalysisExplicitResultParserTests.swift in Sources */,\n\t\t\t\t274C6D3923FBAF5E0090BC40 /* StringUtilsTest.swift in Sources */,\n\t\t\t\t274C6D2D23FBAF5E0090BC40 /* CryptoUtilsTests.swift in Sources */,\n\t\t\t\tD7E79DCC24B515260082288A /* UploaderMockOcrTests.m in Sources */,\n\t\t\t\tD79AE39C24585533004F2439 /* CLDVariableTests.m in Sources */,\n\t\t\t\tD7F34F9125120E0D00C282B1 /* UploaderWidgetEditViewControllerTests.swift in Sources */,\n\t\t\t\tD7519FEC25E26BE9006839B1 /* DownloaderAssetTests.swift in Sources */,\n\t\t\t\tD71B790024680773004AA28E /* CLDTransformationExpressionsTests.swift in Sources */,\n\t\t\t\tD7E79DCE24B515260082288A /* ExplicitMockOcrTests.swift in Sources */,\n\t\t\t\t272C5186242B6C360093AB1B /* MultipartFormDataTests.swift in Sources */,\n\t\t\t\tD7EF05B1255D8C1900F93827 /* UploaderWidgetTests.m in Sources */,\n\t\t\t\t1E635A8525A7585E0003E9D3 /* ObjcQualityAnalysisUploadResultParserTests.m in Sources */,\n\t\t\t\tD7289C8A258A9E18004DBD29 /* UploaderWidgetVideoViewTests.swift in Sources */,\n\t\t\t\t272C5180242B6C360093AB1B /* FileManager+CloudinaryTests.swift in Sources */,\n\t\t\t\tD71ADD9C247D976500235AD4 /* CryptoUtilsTests.m in Sources */,\n\t\t\t\t272C5187242B6C360093AB1B /* URLProtocolTests.swift in Sources */,\n\t\t\t\t272C517F242B6C360093AB1B /* SessionManagerTests.swift in Sources */,\n\t\t\t\tB6AF51632D4A2A430037965A /* NetworkTestUtils.swift in Sources */,\n\t\t\t\t274C6D3823FBAF5E0090BC40 /* DownloaderTests.swift in Sources */,\n\t\t\t\t5D7C2DCF245E93F7007E95F7 /* CLDExpressionTests.swift in Sources */,\n\t\t\t\t272C51B0242B6C360093AB1B /* UploadTests.swift in Sources */,\n\t\t\t\t274C6D3723FBAF5E0090BC40 /* ManagementApiTests.swift in Sources */,\n\t\t\t\tD7EF05B0255D8C1900F93827 /* UploaderWidgetTests.swift in Sources */,\n\t\t\t\tD7119CE3246C7C8100F6B3ED /* CLDConditionExpressionHelpersTests.swift in Sources */,\n\t\t\t\tD7289C88258A9E18004DBD29 /* UploaderWidgetVideoPlayerTests.swift in Sources */,\n\t\t\t\t274C6D3123FBAF5E0090BC40 /* UrlTests.swift in Sources */,\n\t\t\t\tB694AAF52B308C5A00075041 /* VideoEventsManagerTests.swift in Sources */,\n\t\t\t\tD7567064255D661F005B65D3 /* UploaderWidgetViewControllerTests.swift in Sources */,\n\t\t\t\tD7F34F2F2504F48C00C282B1 /* UploaderWidgetCollectionCellTests.swift in Sources */,\n\t\t\t\tD79AE387244DF1E7004F2439 /* CLDVariableTests.swift in Sources */,\n\t\t\t\t1E635A8025A7585E0003E9D3 /* ObjcUploaderQualityAnalysisTests.m in Sources */,\n\t\t\t\t272C5181242B6C360093AB1B /* AuthenticationTests.swift in Sources */,\n\t\t\t\tD7EF05AB255D8B8E00F93827 /* NetworkBaseTest.swift in Sources */,\n\t\t\t\tD7E79DD124B515650082288A /* UploadRequestParamsTests.swift in Sources */,\n\t\t\t\tD71B78FE24680743004AA28E /* CLDTransformationVariablesTests.swift in Sources */,\n\t\t\t\t1E635A8125A7585E0003E9D3 /* QualityAnalysisUploadResultParserTests.swift in Sources */,\n\t\t\t\t5D53A9512488CE23005C14AB /* CLDConfigurationTests.swift in Sources */,\n\t\t\t\tD779B69724B7117300E496EB /* UploaderAccessibilityTests.swift in Sources */,\n\t\t\t\t27BC1FB02431C48D000AFC2C /* CLDNResult+CloudinaryTests.swift in Sources */,\n\t\t\t\tB6F11F3D288FC20900A895CD /* CLDAnalyticsTests.swift in Sources */,\n\t\t\t\t1E635A7F25A7585E0003E9D3 /* MockProviderQualityAnalysis.swift in Sources */,\n\t\t\t\tD73117582473D7A30051AAFC /* CLDExpressionTests.m in Sources */,\n\t\t\t\t1E635A8325A7585E0003E9D3 /* UploaderQualityAnalysisTests.swift in Sources */,\n\t\t\t\tB60F3C222D4B86AF00160FFC /* TestableCloudinary.swift in Sources */,\n\t\t\t\t1E635A3E25A756870003E9D3 /* ObjcBaseTestCase.m in Sources */,\n\t\t\t\tB6B4C49F2C56152700C9B604 /* VideoPreprocessTests.swift in Sources */,\n\t\t\t\t274C6D3323FBAF5E0090BC40 /* UIButtonTests.swift in Sources */,\n\t\t\t\t274C6D3223FBAF5E0090BC40 /* UIBaseTest.swift in Sources */,\n\t\t\t\t5DB2D29924FFE32500001845 /* UploaderWidgetConfigurationTests.m in Sources */,\n\t\t\t\t1E635A7025A757DA0003E9D3 /* BaseMockProvider.swift in Sources */,\n\t\t\t\t274C6D2E23FBAF5E0090BC40 /* PreprocessTests.swift in Sources */,\n\t\t\t\tB6C2D4882A72741B00AA0039 /* CLDVideoPlayerTests.swift in Sources */,\n\t\t\t\tD731175C24741FBE0051AAFC /* CLDTransformationTests.m in Sources */,\n\t\t\t\t274C6D3423FBAF5E0090BC40 /* UIImageViewTests.swift in Sources */,\n\t\t\t\tD7289C81258A9D0B004DBD29 /* UploaderWidgetAssetContainerTests.swift in Sources */,\n\t\t\t\tD731175A247415340051AAFC /* CLDConditionExpressionTests.m in Sources */,\n\t\t\t\t272C51B5242B6C360093AB1B /* ParameterEncodingTests.swift in Sources */,\n\t\t\t\t274C6D2F23FBAF5E0090BC40 /* FileUtilsTests.swift in Sources */,\n\t\t\t\tD7E79DCA24B515260082288A /* OcrMockProvider.swift in Sources */,\n\t\t\t\t5D4D8C2D246098F900AE9C96 /* CLDConditionExpressionTests.swift in Sources */,\n\t\t\t\tD79AE385244CC1D7004F2439 /* CLDTransformationTests.swift in Sources */,\n\t\t\t\t5DE4EC202469919A00F6C8D6 /* CLDTransformationBaselineTests.swift in Sources */,\n\t\t\t\tD7289C89258A9E18004DBD29 /* UploaderWidgetVideoDisplayLinkTests.swift in Sources */,\n\t\t\t\t27BC1FAE2431C3F6000AFC2C /* CLDNDataResponse+CloudinaryTests.swift in Sources */,\n\t\t\t\tD7F34F3325052FE700C282B1 /* WidgetBaseTest.swift in Sources */,\n\t\t\t\tB694AAF32B308C3C00075041 /* VideoEventsTests.swift in Sources */,\n\t\t\t\tD7F34F3125052FBD00C282B1 /* UploaderWidgetPreviewViewControllerTests.swift in Sources */,\n\t\t\t\t272C5182242B6C360093AB1B /* RequestTests.swift in Sources */,\n\t\t\t\tD7E79DC924B515260082288A /* UploaderOcrTests.swift in Sources */,\n\t\t\t\t272C51B3242B6C360093AB1B /* CLDNError+CloudinaryTests.swift in Sources */,\n\t\t\t\tD779B69824B7117300E496EB /* UploaderAccessibilityTests.m in Sources */,\n\t\t\t\tD7EF05AC255D8B8E00F93827 /* NetworkBaseTestObjc.m in Sources */,\n\t\t\t\tD7289C87258A9E18004DBD29 /* UploaderWidgetVideoControlsTests.swift in Sources */,\n\t\t\t\t272C5185242B6C360093AB1B /* ResponseSerializationTests.swift in Sources */,\n\t\t\t\t272C5183242B6C360093AB1B /* SessionDelegateTests.swift in Sources */,\n\t\t\t\t1E635A8225A7585E0003E9D3 /* ObjcQualityAnalysisExplicitResultParserTests.m in Sources */,\n\t\t\t\t5D53A9522488CE23005C14AB /* CLDConfigurationTests.m in Sources */,\n\t\t\t\tD7E79DCB24B515260082288A /* ExplicitMockOcrTests.m in Sources */,\n\t\t\t\tD71B7902246808EE004AA28E /* CLDTransformationConditionsTests.swift in Sources */,\n\t\t\t\t274C6D3623FBAF5E0090BC40 /* UploaderTests.swift in Sources */,\n\t\t\t\tD7E79DCD24B515260082288A /* UploaderMockOcrTests.swift in Sources */,\n\t\t\t\t272C51B1242B6C360093AB1B /* CacheTests.swift in Sources */,\n\t\t\t\t274C6D3023FBAF5E0090BC40 /* UrlTests.m in Sources */,\n\t\t\t\t272C518C242B6C360093AB1B /* BaseTestCase.swift in Sources */,\n\t\t\t\t5D4D8C2E24609C1400AE9C96 /* ValidationTests.swift in Sources */,\n\t\t\t\t272C51B4242B6C360093AB1B /* ResultTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tD7173491258296CE006F34CD /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tD7173498258296CE006F34CD /* WidgetUITests.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\t607FACE71AFB9204008FA782 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 607FACCF1AFB9204008FA782 /* Cloudinary_Example */;\n\t\t\ttargetProxy = 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */;\n\t\t};\n\t\tD717349B258296CE006F34CD /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 607FACCF1AFB9204008FA782 /* Cloudinary_Example */;\n\t\t\ttargetProxy = D717349A258296CE006F34CD /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tB64ED1C72B8C933A00BE653E /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1C82B8C933A00BE653E /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB64ED1C92B8C933A00BE653E /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tB64ED1CA2B8C933A00BE653E /* 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\t607FACED1AFB9204008FA782 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_SYMBOLS_PRIVATE_EXTERN = NO;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.3;\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\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t607FACEE1AFB9204008FA782 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Owholemodule\";\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t607FACF01AFB9204008FA782 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = DE971235B5CF94F0DA4D461B /* Pods-Cloudinary_Example.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1.0;\n\t\t\t\tDEVELOPMENT_TEAM = 3TR999VVAS;\n\t\t\t\tINFOPLIST_FILE = Cloudinary/Info.plist;\n\t\t\t\tINFOPLIST_KEY_CFBundleDisplayName = Cloudinary;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tMARKETING_VERSION = 1.0.0;\n\t\t\t\tMODULE_NAME = ExampleApp;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Cloudinary/Cloudinary_Example-Bridging-Header.h\";\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};\n\t\t\tname = Debug;\n\t\t};\n\t\t607FACF11AFB9204008FA782 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = E5BA1162DEC8D6E579692502 /* Pods-Cloudinary_Example.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1.0;\n\t\t\t\tDEVELOPMENT_TEAM = 3TR999VVAS;\n\t\t\t\tINFOPLIST_FILE = Cloudinary/Info.plist;\n\t\t\t\tINFOPLIST_KEY_CFBundleDisplayName = Cloudinary;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tMARKETING_VERSION = 1.0.0;\n\t\t\t\tMODULE_NAME = ExampleApp;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OBJC_BRIDGING_HEADER = \"Cloudinary/Cloudinary_Example-Bridging-Header.h\";\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Default;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t607FACF31AFB9204008FA782 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = 2F5D96AD5982EFEBDEE91350 /* Pods-Cloudinary_Tests.debug.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=macosx*]\" = \"-\";\n\t\t\t\tDEVELOPMENT_TEAM = 3TR999VVAS;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(PLATFORM_DIR)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = Tests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\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)/Cloudinary_Example.app/Cloudinary_Example\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t607FACF41AFB9204008FA782 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbaseConfigurationReference = FB8B4986C00FEC3B8BD40223 /* Pods-Cloudinary_Tests.release.xcconfig */;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=macosx*]\" = \"-\";\n\t\t\t\tDEVELOPMENT_TEAM = 3TR999VVAS;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(PLATFORM_DIR)/Developer/Library/Frameworks\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = Tests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\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)/Cloudinary_Example.app/Cloudinary_Example\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tD717349D258296CE006F34CD /* 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_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = 69UZJ87W84;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tINFOPLIST_FILE = WidgetUITests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.demo.WidgetUITests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTEST_TARGET_NAME = Cloudinary_Example;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tD717349E258296CE006F34CD /* 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_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = 69UZJ87W84;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tINFOPLIST_FILE = WidgetUITests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks @loader_path/Frameworks\";\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.demo.WidgetUITests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTEST_TARGET_NAME = Cloudinary_Example;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject \"Cloudinary\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t607FACED1AFB9204008FA782 /* Debug */,\n\t\t\t\t607FACEE1AFB9204008FA782 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget \"Cloudinary_Example\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t607FACF01AFB9204008FA782 /* Debug */,\n\t\t\t\t607FACF11AFB9204008FA782 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget \"Cloudinary_Tests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t607FACF31AFB9204008FA782 /* Debug */,\n\t\t\t\t607FACF41AFB9204008FA782 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tD717349C258296CE006F34CD /* Build configuration list for PBXNativeTarget \"Cloudinary_UITests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tD717349D258296CE006F34CD /* Debug */,\n\t\t\t\tD717349E258296CE006F34CD /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCVersionGroup section */\n\t\tB64120C92C48EF10005A5495 /* AssetModel.xcdatamodeld */ = {\n\t\t\tisa = XCVersionGroup;\n\t\t\tchildren = (\n\t\t\t\tB64120CA2C48EF10005A5495 /* Model.xcdatamodel */,\n\t\t\t);\n\t\t\tcurrentVersion = B64120CA2C48EF10005A5495 /* Model.xcdatamodel */;\n\t\t\tpath = AssetModel.xcdatamodeld;\n\t\t\tsourceTree = \"<group>\";\n\t\t\tversionGroupType = wrapper.xcdatamodel;\n\t\t};\n/* End XCVersionGroup section */\n\t};\n\trootObject = 607FACC81AFB9204008FA782 /* Project object */;\n}\n"
  },
  {
    "path": "Example/Cloudinary.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:Cloudinary.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Example/Cloudinary.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Example/Cloudinary.xcodeproj/xcshareddata/xcschemes/Cloudinary-Example.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1250\"\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 = \"607FACCF1AFB9204008FA782\"\n               BuildableName = \"Cloudinary_Example.app\"\n               BlueprintName = \"Cloudinary_Example\"\n               ReferencedContainer = \"container:Cloudinary.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"607FACE41AFB9204008FA782\"\n               BuildableName = \"Cloudinary_Tests.xctest\"\n               BlueprintName = \"Cloudinary_Tests\"\n               ReferencedContainer = \"container:Cloudinary.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 = \"NO\"\n      codeCoverageEnabled = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"607FACCF1AFB9204008FA782\"\n            BuildableName = \"Cloudinary_Example.app\"\n            BlueprintName = \"Cloudinary_Example\"\n            ReferencedContainer = \"container:Cloudinary.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"607FACE41AFB9204008FA782\"\n               BuildableName = \"Cloudinary_Tests.xctest\"\n               BlueprintName = \"Cloudinary_Tests\"\n               ReferencedContainer = \"container:Cloudinary.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 = \"607FACCF1AFB9204008FA782\"\n            BuildableName = \"Cloudinary_Example.app\"\n            BlueprintName = \"Cloudinary_Example\"\n            ReferencedContainer = \"container:Cloudinary.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 = \"607FACCF1AFB9204008FA782\"\n            BuildableName = \"Cloudinary_Example.app\"\n            BlueprintName = \"Cloudinary_Example\"\n            ReferencedContainer = \"container:Cloudinary.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": "Example/Cloudinary.xcodeproj/xcshareddata/xcschemes/travis_public_scheme.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1250\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"NO\"\n            buildForArchiving = \"NO\"\n            buildForAnalyzing = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"607FACE41AFB9204008FA782\"\n               BuildableName = \"Cloudinary_Tests.xctest\"\n               BlueprintName = \"Cloudinary_Tests\"\n               ReferencedContainer = \"container:Cloudinary.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"607FACE41AFB9204008FA782\"\n               BuildableName = \"Cloudinary_Tests.xctest\"\n               BlueprintName = \"Cloudinary_Tests\"\n               ReferencedContainer = \"container:Cloudinary.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      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"607FACE41AFB9204008FA782\"\n            BuildableName = \"Cloudinary_Tests.xctest\"\n            BlueprintName = \"Cloudinary_Tests\"\n            ReferencedContainer = \"container:Cloudinary.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": "Example/Podfile",
    "content": "platform :ios, '13.0'\nuse_frameworks!\n\ntarget 'Cloudinary_Example' do\n  pod 'Cloudinary', :path => '../'\n#  pod 'Firebase'\n\n  target 'Cloudinary_Tests' do\n    inherit! :search_paths\n    \n    # For view base tests add FBSnapshotTestCase\n    #pod 'FBSnapshotTestCase' , '~> 2.1.4'\n  end\nend\n"
  },
  {
    "path": "Example/README.md",
    "content": "## Introduction\nThis is a very simple application that integrates the [Cloudinary iOS SDK](https://github.com/cloudinary/cloudinary_ios).\nThe application has the following samples:\n1. Delivery\n  1. Optimization\n  2. Transform\n  3. Use cases\n2. Upload\n   1. Upload\n   2. Upload large\n   3. Fetch upload\n3. UI\n   1. Upload Widget\n   2. Image Widget\n4. Video\n    1. Video Widget\n    2. Video feed\n\n## Installation\nTo use the sample project please go to the Example directory and run the following command:\n\n```bash\npod install\n```\n\n## Configuration\nOnce you clone this repository there are two required steps to build the sample app:\n1. Configure your Cloudinary cloud name for the app:\n    * Once you open the upload controller you'll be asked to enter your cloud name, you can find your cloud name at the top of your [dashboard.](https://console.cloudinary.com/pm/developer-dashboard)\n2. Create an upload preset named 'ios_sample' in your cloudinary account console:\n    *  Login to your [Cloudinary console](https://cloudinary.com/console), go to settings>upload, scroll down\n      to Upload Presets and click `Add upload preset`. Alternatively, head directly to the [new preset page](https://console.cloudinary.com/console/upload_presets/new).\n    * Type in `ios_sample` as the name and save, leaving all the fields with their default values.\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/BaseTestCase.swift",
    "content": "//\n//  BaseTestCase.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass BaseTestCase: XCTestCase {\n    let timeout: TimeInterval = 120.0\n\n    static var testDirectoryURL: URL { return FileManager.temporaryDirectoryURL.appendingPathComponent(\"org.cloudinary.tests\") }\n    var testDirectoryURL: URL { return BaseTestCase.testDirectoryURL }\n\n    override func setUp() {\n        super.setUp()\n\n        FileManager.removeAllItemsInsideDirectory(at: testDirectoryURL)\n        FileManager.createDirectory(at: testDirectoryURL)\n    }\n\n    override func setUpWithError() throws {\n        \n        try XCTSkipIf(shouldSkipTest(), \"test skipped\")\n        \n        try super.setUpWithError()\n    }\n    \n    /**\n     override this method to skip tests when needed\n    */\n    func shouldSkipTest() -> Bool {\n        return false\n    }\n    \n    func url(forResource fileName: String, withExtension ext: String) -> URL {\n        let bundle = Bundle(for: BaseTestCase.self)\n        return bundle.url(forResource: fileName, withExtension: ext)!\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Core/AuthenticationTests.swift",
    "content": "//\n//  AuthenticationTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass AuthenticationTestCase: BaseTestCase {\n    let user = \"user\"\n    let password = \"password\"\n    var urlString = \"\"\n\n    var manager: CLDNSessionManager!\n\n    override func setUp() {\n        super.setUp()\n\n        manager = CLDNSessionManager(configuration: .default)\n\n        // Clear out credentials\n        let credentialStorage = URLCredentialStorage.shared\n\n        for (protectionSpace, credentials) in credentialStorage.allCredentials {\n            for (_, credential) in credentials {\n                credentialStorage.remove(credential, for: protectionSpace)\n            }\n        }\n\n        // Clear out cookies\n        let cookieStorage = HTTPCookieStorage.shared\n        cookieStorage.cookies?.forEach { cookieStorage.deleteCookie($0) }\n    }\n}\n\n// MARK: -\n\nclass BasicAuthenticationTestCase: AuthenticationTestCase {\n    override func setUp() {\n        super.setUp()\n        urlString = \"https://httpbin.org/\"\n    }\n\n    func skipped_testHTTPBasicAuthenticationWithInvalidCredentials() {\n        // Given\n        let expectation = self.expectation(description: \"\\(urlString) 401\")\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        let credentials = \"\\(user):\\(password)\".data(using: .utf8)?.base64EncodedString()\n        manager.request(urlString, headers: [\"Authorization\": \"Basic \\(credentials ?? \"\")\"])\n            .authenticate(user: \"invalid\", password: \"credentials\")\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertEqual(response?.response?.statusCode, 401)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n    }\n\n    func testHTTPBasicAuthenticationWithValidCredentials() {\n        // Given\n        let expectation = self.expectation(description: \"\\(urlString) 200\")\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .authenticate(user: user, password: password)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertEqual(response?.response?.statusCode, 200)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n    }\n\n    func testHiddenHTTPBasicAuthentication() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n        let expectation = self.expectation(description: \"\\(urlString) 200\")\n\n        var headers: CLDNHTTPHeaders?\n\n        if let authorizationHeader = CLDNRequest.authorizationHeader(user: user, password: password) {\n            headers = [authorizationHeader.key: authorizationHeader.value]\n        }\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString, headers: headers)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertEqual(response?.response?.statusCode, 200)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n    }\n}\n\n// MARK: -\n\nclass HTTPDigestAuthenticationTestCase: AuthenticationTestCase {\n    let qop = \"auth\"\n\n    override func setUp() {\n        super.setUp()\n        urlString = \"https://httpbin.org/\"\n    }\n\n    func skipped_testHTTPDigestAuthenticationWithInvalidCredentials() {\n        // Given\n        let expectation = self.expectation(description: \"\\(urlString) 401\")\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .authenticate(user: \"invalid\", password: \"credentials\")\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertEqual(response?.response?.statusCode, 401)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n    }\n\n    func testHTTPDigestAuthenticationWithValidCredentials() {\n        // Given\n        let expectation = self.expectation(description: \"\\(urlString) 200\")\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .authenticate(user: user, password: password)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertEqual(response?.response?.statusCode, 200)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Core/CLDCloudinaryTests.m",
    "content": "//\n//  CLDCloudinaryTests.m\n//\n//  Copyright (c) 2021 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"Cloudinary_Tests-Swift.h\"\n#import \"NetworkBaseTestObjc.h\"\n\n@interface CLDCustomAdapter: NSObject  <CLDNetworkAdapter>\n@end\n\n@implementation CLDCustomAdapter\n- (id<CLDNetworkDataRequest> _Nonnull)cloudinaryRequest:(NSString * _Nonnull)url headers:(NSDictionary<NSString *,NSString *> * _Nonnull)headers parameters:(NSDictionary<NSString *,id> * _Nonnull)parameters {return nil;}\n- (id<CLDFetchImageRequest> _Nonnull)downloadFromCloudinary:(NSString * _Nonnull)url {return nil;}\n- (void (^ _Nullable)(void))getBackgroundCompletionHandler {return nil;}\n- (void)setBackgroundCompletionHandler:(void (^ _Nullable)(void))newValue {}\n- (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads {}\n- (id<CLDNetworkDataRequest> _Nonnull)uploadToCloudinary:(NSString * _Nonnull)url headers:(NSDictionary<NSString *,NSString *> * _Nonnull)headers parameters:(NSDictionary<NSString *,id> * _Nonnull)parameters data:(id _Nonnull)data {return nil;}\n@end\n\n@interface CLDCloudinaryTests: XCTestCase\n@property (nonatomic, strong, nullable) CLDCloudinary* sut;\n@property (nonatomic, strong, nullable) CLDConfiguration* config;\n@end\n\n@implementation CLDCloudinaryTests\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n    \n    self.config = [[CLDConfiguration alloc] initWithCloudinaryUrl:@\"cloudinary://a:b@test123\"];\n    self.sut    = [[CLDCloudinary alloc] initWithConfiguration: self.config networkAdapter:nil sessionConfiguration:nil];\n}\n\n- (void)tearDown {\n    \n    self.sut = nil;\n    self.config = nil;\n    [super tearDown];\n}\n\n// MARK: - init\n- (void)test_init_config_shouldStoreProperties {\n\n    // Given\n    NSString* cloudinaryUrl = @\"cloudinary://a:b@test123\";\n    CLDConfiguration* tempConfiguration = [[CLDConfiguration alloc] initWithCloudinaryUrl:cloudinaryUrl];\n    \n    // When\n    CLDCloudinary   * tempSut           = [[CLDCloudinary alloc] initWithConfiguration:tempConfiguration networkAdapter:nil sessionConfiguration:nil];\n    \n    // Then\n    XCTAssertNotNil(tempSut, \"initialized object should not be nil\");\n    XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\");\n}\n- (void)test_init_configSession_shouldStoreProperties {\n\n    // Given\n    NSString                  * cloudinaryUrl     = @\"cloudinary://a:b@test123\";\n    NSURLSessionConfiguration *sessionConfig      = [NSURLSessionConfiguration defaultSessionConfiguration];\n    CLDConfiguration          * tempConfiguration = [[CLDConfiguration alloc] initWithCloudinaryUrl:cloudinaryUrl];\n    \n    // When\n    CLDCloudinary* tempSut = [[CLDCloudinary alloc] initWithConfiguration:tempConfiguration networkAdapter:nil sessionConfiguration:sessionConfig];\n    \n    // Then\n    XCTAssertNotNil(tempSut, \"initialized object should not be nil\");\n    XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\");\n}\n- (void)test_init_configDownloadSession_shouldStoreProperties {\n\n    // Given\n    NSString                  * cloudinaryUrl = @\"cloudinary://a:b@test123\";\n    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];\n    CLDConfiguration          * tempConfiguration = [[CLDConfiguration alloc] initWithCloudinaryUrl:cloudinaryUrl];\n    \n    // When\n    CLDCloudinary* tempSut = [[CLDCloudinary alloc] initWithConfiguration:tempConfiguration networkAdapter:nil downloadAdapter:nil sessionConfiguration:sessionConfig downloadSessionConfiguration:sessionConfig];\n    \n    // Then\n    XCTAssertNotNil(tempSut, \"initialized object should not be nil\");\n    XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\");\n}\n- (void)test_init_configDownloadSessionAdapter_shouldStoreProperties {\n\n    // Given\n    NSString                  * cloudinaryUrl = @\"cloudinary://a:b@test123\";\n    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];\n    CLDConfiguration          * tempConfiguration = [[CLDConfiguration alloc] initWithCloudinaryUrl:cloudinaryUrl];\n    CLDCustomAdapter          * adapter           = [[CLDCustomAdapter alloc] init];\n    \n    // When\n    CLDCloudinary* tempSut = [[CLDCloudinary alloc] initWithConfiguration:tempConfiguration networkAdapter:adapter downloadAdapter:nil sessionConfiguration:sessionConfig downloadSessionConfiguration:sessionConfig];\n    \n    // Then\n    XCTAssertNotNil(tempSut, \"initialized object should not be nil\");\n    XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\");\n}\n- (void)test_init_configDownloadSessionDownloadAdapter_shouldStoreProperties {\n\n    // Given\n    NSString                  * cloudinaryUrl = @\"cloudinary://a:b@test123\";\n    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];\n    CLDConfiguration          * tempConfiguration = [[CLDConfiguration alloc] initWithCloudinaryUrl:cloudinaryUrl];\n    CLDCustomAdapter          * adapter           = [[CLDCustomAdapter alloc] init];\n    \n    // When\n    CLDCloudinary* tempSut = [[CLDCloudinary alloc] initWithConfiguration:tempConfiguration networkAdapter:adapter downloadAdapter:adapter sessionConfiguration:sessionConfig downloadSessionConfiguration:sessionConfig];\n    \n    // Then\n    XCTAssertNotNil(tempSut, \"initialized object should not be nil\");\n    XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\");\n}\n- (void)test_init_configSessionAdapter_shouldStoreProperties {\n\n    // Given\n    NSString                  * cloudinaryUrl = @\"cloudinary://a:b@test123\";\n    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];\n    CLDConfiguration          * tempConfiguration = [[CLDConfiguration alloc] initWithCloudinaryUrl:cloudinaryUrl];\n    CLDCustomAdapter          * adapter           = [[CLDCustomAdapter alloc] init];\n\n    // When\n    CLDCloudinary* tempSut = [[CLDCloudinary alloc] initWithConfiguration:tempConfiguration networkAdapter:adapter sessionConfiguration:sessionConfig];\n    \n    // Then\n    XCTAssertNotNil(tempSut, \"initialized object should not be nil\");\n    XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Core/CLDCloudinaryTests.swift",
    "content": "//\n//  CLDCloudinaryTests.swift\n//\n//  Copyright (c) 2021 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass CLDCloudinaryTests: XCTestCase {\n\n    var sut   : CLDCloudinary!\n    var config: CLDConfiguration!\n    \n    override func setUp() {\n        super.setUp()\n        \n        config = CLDConfiguration(cloudinaryUrl: \"cloudinary://a:b@test123\")!\n        sut    = CLDCloudinary(configuration: config, sessionConfiguration: .default)\n    }\n    \n    override func tearDownWithError() throws {\n        sut    = nil\n        config = nil\n        super.tearDown()\n    }\n    \n    // MARK: - init\n    func test_init_config_shouldStoreProperties() {\n        \n        // Given\n        let cloudinaryUrl     = \"cloudinary://a:b@test123\"\n        let tempConfiguration = CLDConfiguration(cloudinaryUrl: cloudinaryUrl)!\n        \n        // When\n        let tempSut           = CLDCloudinary(configuration: tempConfiguration)\n\n        // Then\n        XCTAssertNotNil(tempSut, \"initialized object should not be nil\")\n        XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\")\n    }\n    \n    func test_init_configSession_shouldStoreProperties() {\n        \n        // Given\n        let cloudinaryUrl     = \"cloudinary://a:b@test123\"\n        let tempConfiguration = CLDConfiguration(cloudinaryUrl: cloudinaryUrl)!\n\n        // When\n        let tempSut           = CLDCloudinary(configuration: tempConfiguration, sessionConfiguration: .default)\n\n        // Then\n        XCTAssertNotNil(tempSut, \"initialized object should not be nil\")\n        XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\")\n    }\n    func test_init_configDownloadSession_shouldStoreProperties() {\n        \n        // Given\n        let cloudinaryUrl     = \"cloudinary://a:b@test123\"\n        let tempConfiguration = CLDConfiguration(cloudinaryUrl: cloudinaryUrl)!\n\n        // When\n        let tempSut           = CLDCloudinary(configuration: tempConfiguration, sessionConfiguration: .default, downloadSessionConfiguration: .default)\n\n        // Then\n        XCTAssertNotNil(tempSut, \"initialized object should not be nil\")\n        XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\")\n    }\n    func test_init_configDownloadSessionAdapter_shouldStoreProperties() {\n        \n        // Given\n        let adapter           = CLDDefaultNetworkAdapter()\n        let cloudinaryUrl     = \"cloudinary://a:b@test123\"\n        let tempConfiguration = CLDConfiguration(cloudinaryUrl: cloudinaryUrl)!\n\n        // When\n        let tempSut           = CLDCloudinary(configuration: tempConfiguration, networkAdapter: adapter, downloadAdapter: nil, sessionConfiguration: .default, downloadSessionConfiguration: .default)\n\n        // Then\n        XCTAssertNotNil(tempSut, \"initialized object should not be nil\")\n        XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\")\n    }\n    func test_init_configDownloadSessionDownloadAdapter_shouldStoreProperties() {\n        \n        // Given\n        let adapter           = CLDDefaultNetworkAdapter()\n        let cloudinaryUrl     = \"cloudinary://a:b@test123\"\n        let tempConfiguration = CLDConfiguration(cloudinaryUrl: cloudinaryUrl)!\n\n        // When\n        let tempSut           = CLDCloudinary(configuration: tempConfiguration, networkAdapter: adapter, downloadAdapter: adapter, sessionConfiguration: .default, downloadSessionConfiguration: .default)\n\n        // Then\n        XCTAssertNotNil(tempSut, \"initialized object should not be nil\")\n        XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\")\n    }\n    func test_init_configSessionAdapter_shouldStoreProperties() {\n        \n        // Given\n        let adapter           = CLDDefaultNetworkAdapter()\n        let cloudinaryUrl     = \"cloudinary://a:b@test123\"\n        let tempConfiguration = CLDConfiguration(cloudinaryUrl: cloudinaryUrl)!\n\n        // When\n        let tempSut           = CLDCloudinary(configuration: tempConfiguration, networkAdapter: adapter, sessionConfiguration: .default)\n        \n        // Then\n        XCTAssertNotNil(tempSut, \"initialized object should not be nil\")\n        XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\")\n    }\n\n    func test_init_configSessionAdapter_shouldStoreExtraHeaders() {\n\n        // Given\n        let extraHeaders      = [\"Test\": \"Test\"]\n        var adapter           = CLDDefaultNetworkAdapter()\n        let cloudinaryUrl     = \"cloudinary://a:b@test123\"\n        let tempConfiguration = CLDConfiguration(cloudinaryUrl: cloudinaryUrl)!\n\n        // When\n        let tempSut           = CLDCloudinary(configuration: tempConfiguration, networkAdapter: adapter, sessionConfiguration: .default)\n        tempSut.setExtraHeaderes(extraHeaders)\n\n        // Then\n        XCTAssertNotNil(tempSut, \"initialized object should not be nil\")\n        XCTAssertEqual (tempSut.config, tempConfiguration, \"Initilized object should contain expected value\")\n    }\n\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Core/ParameterEncodingTests.swift",
    "content": "//\n//  ParameterEncodingTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass ParameterEncodingTestCase: BaseTestCase {\n    let urlRequest = URLRequest(url: URL(string: \"https://example.com/\")!)\n\n    internal func checkParamsEncodedCorrectly(params: [String: Any], encoding: CLDNURLEncoding = CLDNURLEncoding.default) throws {\n        var request = urlRequest\n        request.httpMethod = CLDNHTTPMethod.post.rawValue\n\n        let encodedURLRequest = try encoding.CLDN_Encode(request, with: params)\n\n        XCTAssertNotNil(encodedURLRequest.httpBody, \"HTTPBody should not be nil\")\n\n        let queryParams = params.map({\n            encoding.queryComponents(fromKey: $0, value: $1)\n        }).reduce([], +)\n\n        if let httpBody = encodedURLRequest.httpBody, let decodedHTTPBody = String(data: httpBody, encoding: .utf8) {\n            for query in queryParams {\n                XCTAssert(decodedHTTPBody.contains(\"\\(query.0)=\\(query.1)\"))\n            }\n        } else {\n            XCTFail(\"decoded http body should not be nil\")\n        }\n    }\n}\n\n// MARK: -\n\nclass URLParameterEncodingTestCase: ParameterEncodingTestCase {\n\n    // MARK: Properties\n\n    let encoding = CLDNURLEncoding.default\n\n    // MARK: Tests - Parameter Types\n\n    func testURLParameterEncodeNilParameters() {\n        do {\n            // Given, When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: nil)\n\n            // Then\n            XCTAssertNil(urlRequest.url?.query)\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeEmptyDictionaryParameter() {\n        do {\n            // Given\n            let parameters: [String: Any] = [:]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertNil(urlRequest.url?.query)\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeOneStringKeyStringValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": \"bar\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo=bar\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeOneStringKeyStringValueParameterAppendedToQuery() {\n        do {\n            // Given\n            var mutableURLRequest = self.urlRequest\n            var urlComponents = URLComponents(url: mutableURLRequest.url!, resolvingAgainstBaseURL: false)!\n            urlComponents.query = \"baz=qux\"\n            mutableURLRequest.url = urlComponents.url\n\n            let parameters = [\"foo\": \"bar\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(mutableURLRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"baz=qux&foo=bar\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeTwoStringKeyStringValueParameters() {\n        do {\n            // Given\n            let parameters = [\"foo\": \"bar\", \"baz\": \"qux\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"baz=qux&foo=bar\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyNSNumberIntegerValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": NSNumber(value: 25)]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo=25\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyNSNumberBoolValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": NSNumber(value: false)]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo=0\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyIntegerValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": 1]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo=1\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyDoubleValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": 1.1]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo=1.1\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyBoolValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": true]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo=1\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyArrayValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": [\"a\", 1, true]]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo%5B%5D=a&foo%5B%5D=1&foo%5B%5D=1\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyArrayValueParameterWithoutBrackets() {\n        do {\n            // Given\n            let encoding = CLDNURLEncoding(arrayEncoding: .noBrackets)\n            let parameters = [\"foo\": [\"a\", 1, true]]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo=a&foo=1&foo=1\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyDictionaryValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": [\"bar\": 1]]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo%5Bbar%5D=1\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyNestedDictionaryValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": [\"bar\": [\"baz\": 1]]]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo%5Bbar%5D%5Bbaz%5D=1\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyNestedDictionaryArrayValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": [\"bar\": [\"baz\": [\"a\", 1, true]]]]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            let expectedQuery = \"foo%5Bbar%5D%5Bbaz%5D%5B%5D=a&foo%5Bbar%5D%5Bbaz%5D%5B%5D=1&foo%5Bbar%5D%5Bbaz%5D%5B%5D=1\"\n            XCTAssertEqual(urlRequest.url?.query, expectedQuery)\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyNestedDictionaryArrayValueParameterWithoutBrackets() {\n        do {\n            // Given\n            let encoding = CLDNURLEncoding(arrayEncoding: .noBrackets)\n            let parameters = [\"foo\": [\"bar\": [\"baz\": [\"a\", 1, true]]]]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            let expectedQuery = \"foo%5Bbar%5D%5Bbaz%5D=a&foo%5Bbar%5D%5Bbaz%5D=1&foo%5Bbar%5D%5Bbaz%5D=1\"\n            XCTAssertEqual(urlRequest.url?.query, expectedQuery)\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterLiteralBoolEncodingWorksAndDoesNotAffectNumbers() {\n        do {\n            // Given\n            let encoding = CLDNURLEncoding(boolEncoding: .literal)\n            let parameters: [String: Any] = [\n                // Must still encode to numbers\n                \"a\": 1,\n                \"b\": 0,\n                \"c\": 1.0,\n                \"d\": 0.0,\n                \"e\": NSNumber(value: 1),\n                \"f\": NSNumber(value: 0),\n                \"g\": NSNumber(value: 1.0),\n                \"h\": NSNumber(value: 0.0),\n\n                // Must encode to literals\n                \"i\": true,\n                \"j\": false,\n                \"k\": NSNumber(value: true),\n                \"l\": NSNumber(value: false)\n            ]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"a=1&b=0&c=1&d=0&e=1&f=0&g=1&h=0&i=true&j=false&k=true&l=false\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    // MARK: Tests - All Reserved / Unreserved / Illegal Characters According to RFC 3986\n\n    func testThatReservedCharactersArePercentEscapedMinusQuestionMarkAndForwardSlash() {\n        do {\n            // Given\n            let generalDelimiters = \":#[]@\"\n            let subDelimiters = \"!$&'()*+,;=\"\n            let parameters = [\"reserved\": \"\\(generalDelimiters)\\(subDelimiters)\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            let expectedQuery = \"reserved=%3A%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D\"\n            XCTAssertEqual(urlRequest.url?.query, expectedQuery)\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testThatReservedCharactersQuestionMarkAndForwardSlashAreNotPercentEscaped() {\n        do {\n            // Given\n            let parameters = [\"reserved\": \"?/\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"reserved=?/\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testThatUnreservedNumericCharactersAreNotPercentEscaped() {\n        do {\n            // Given\n            let parameters = [\"numbers\": \"0123456789\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"numbers=0123456789\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testThatUnreservedLowercaseCharactersAreNotPercentEscaped() {\n        do {\n            // Given\n            let parameters = [\"lowercase\": \"abcdefghijklmnopqrstuvwxyz\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"lowercase=abcdefghijklmnopqrstuvwxyz\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testThatUnreservedUppercaseCharactersAreNotPercentEscaped() {\n        do {\n            // Given\n            let parameters = [\"uppercase\": \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"uppercase=ABCDEFGHIJKLMNOPQRSTUVWXYZ\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testThatIllegalASCIICharactersArePercentEscaped() {\n        do {\n            // Given\n            let parameters = [\"illegal\": \" \\\"#%<>[]\\\\^`{}|\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            let expectedQuery = \"illegal=%20%22%23%25%3C%3E%5B%5D%5C%5E%60%7B%7D%7C\"\n            XCTAssertEqual(urlRequest.url?.query, expectedQuery)\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    // MARK: Tests - Special Character Queries\n\n    func testURLParameterEncodeStringWithAmpersandKeyStringWithAmpersandValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo&bar\": \"baz&qux\", \"foobar\": \"bazqux\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo%26bar=baz%26qux&foobar=bazqux\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringWithQuestionMarkKeyStringWithQuestionMarkValueParameter() {\n        do {\n            // Given\n            let parameters = [\"?foo?\": \"?bar?\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"?foo?=?bar?\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringWithSlashKeyStringWithQuestionMarkValueParameter() {\n        do {\n            // Given\n            let parameters = [\"foo\": \"/bar/baz/qux\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"foo=/bar/baz/qux\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringWithSpaceKeyStringWithSpaceValueParameter() {\n        do {\n            // Given\n            let parameters = [\" foo \": \" bar \"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"%20foo%20=%20bar%20\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringWithPlusKeyStringWithPlusValueParameter() {\n        do {\n            // Given\n            let parameters = [\"+foo+\": \"+bar+\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"%2Bfoo%2B=%2Bbar%2B\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyPercentEncodedStringValueParameter() {\n        do {\n            // Given\n            let parameters = [\"percent\": \"%25\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"percent=%2525\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringKeyNonLatinStringValueParameter() {\n        do {\n            // Given\n            let parameters = [\n                \"french\": \"français\",\n                \"japanese\": \"日本語\",\n                \"arabic\": \"العربية\",\n                \"emoji\": \"😃\"\n            ]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            let expectedParameterValues = [\n                \"arabic=%D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9\",\n                \"emoji=%F0%9F%98%83\",\n                \"french=fran%C3%A7ais\",\n                \"japanese=%E6%97%A5%E6%9C%AC%E8%AA%9E\"\n            ]\n\n            let expectedQuery = expectedParameterValues.joined(separator: \"&\")\n            XCTAssertEqual(urlRequest.url?.query, expectedQuery)\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringForRequestWithPrecomposedQuery() {\n        do {\n            // Given\n            let url = URL(string: \"https://example.com/movies?hd=[1]\")!\n            let parameters = [\"page\": \"0\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(URLRequest(url: url), with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"hd=%5B1%5D&page=0\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringWithPlusKeyStringWithPlusValueParameterForRequestWithPrecomposedQuery() {\n        do {\n            // Given\n            let url = URL(string: \"https://example.com/movie?hd=[1]\")!\n            let parameters = [\"+foo+\": \"+bar+\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(URLRequest(url: url), with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"hd=%5B1%5D&%2Bfoo%2B=%2Bbar%2B\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testURLParameterEncodeStringWithThousandsOfChineseCharacters() {\n        do {\n            // Given\n            let repeatedCount = 2_000\n            let url = URL(string: \"https://example.com/movies\")!\n            let parameters = [\"chinese\": String(repeating: \"一二三四五六七八九十\", count: repeatedCount)]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(URLRequest(url: url), with: parameters)\n\n            // Then\n            var expected = \"chinese=\"\n\n            for _ in 0..<repeatedCount {\n                expected += \"%E4%B8%80%E4%BA%8C%E4%B8%89%E5%9B%9B%E4%BA%94%E5%85%AD%E4%B8%83%E5%85%AB%E4%B9%9D%E5%8D%81\"\n            }\n\n            XCTAssertEqual(urlRequest.url?.query, expected)\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    // MARK: Tests - Varying HTTP Methods\n\n    func testThatURLParameterEncodingEncodesGETParametersInURL() {\n        do {\n            // Given\n            var mutableURLRequest = self.urlRequest\n            mutableURLRequest.httpMethod = CLDNHTTPMethod.get.rawValue\n            let parameters = [\"foo\": 1, \"bar\": 2]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(mutableURLRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"bar=2&foo=1\")\n            XCTAssertNil(urlRequest.value(forHTTPHeaderField: \"Content-Type\"), \"Content-Type should be nil\")\n            XCTAssertNil(urlRequest.httpBody, \"HTTPBody should be nil\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testThatURLParameterEncodingEncodesPOSTParametersInHTTPBody() {\n        do {\n            // Given\n            var mutableURLRequest = self.urlRequest\n            mutableURLRequest.httpMethod = CLDNHTTPMethod.post.rawValue\n            let parameters = [\"foo\": 1, \"bar\": 2]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(mutableURLRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.value(forHTTPHeaderField: \"Content-Type\"), \"application/x-www-form-urlencoded; charset=utf-8\")\n            XCTAssertNotNil(urlRequest.httpBody, \"HTTPBody should not be nil\")\n\n            if let httpBody = urlRequest.httpBody, let decodedHTTPBody = String(data: httpBody, encoding: .utf8) {\n                XCTAssertEqual(decodedHTTPBody, \"bar=2&foo=1\")\n            } else {\n                XCTFail(\"decoded http body should not be nil\")\n            }\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testThatURLEncodedInURLParameterEncodingEncodesPOSTParametersInURL() {\n        do {\n            // Given\n            var mutableURLRequest = self.urlRequest\n            mutableURLRequest.httpMethod = CLDNHTTPMethod.post.rawValue\n            let parameters = [\"foo\": 1, \"bar\": 2]\n\n            // When\n            let urlRequest = try CLDNURLEncoding.queryString.CLDN_Encode(mutableURLRequest, with: parameters)\n\n            // Then\n            XCTAssertEqual(urlRequest.url?.query, \"bar=2&foo=1\")\n            XCTAssertNil(urlRequest.value(forHTTPHeaderField: \"Content-Type\"))\n            XCTAssertNil(urlRequest.httpBody, \"HTTPBody should be nil\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n}\n\n// MARK: -\n\nclass JSONParameterEncodingTestCase: ParameterEncodingTestCase {\n    // MARK: Properties\n\n    let encoding = CLDNJSONEncoding.default\n\n    // MARK: Tests\n\n    func testJSONParameterEncodeNilParameters() {\n        do {\n            // Given, When\n            let URLRequest = try encoding.CLDN_Encode(self.urlRequest, with: nil)\n\n            // Then\n            XCTAssertNil(URLRequest.url?.query, \"query should be nil\")\n            XCTAssertNil(URLRequest.value(forHTTPHeaderField: \"Content-Type\"))\n            XCTAssertNil(URLRequest.httpBody, \"HTTPBody should be nil\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testJSONParameterEncodeComplexParameters() {\n        do {\n            // Given\n            let parameters: [String: Any] = [\n                \"foo\": \"bar\",\n                \"baz\": [\"a\", 1, true],\n                \"qux\": [\n                    \"a\": 1,\n                    \"b\": [2, 2],\n                    \"c\": [3, 3, 3]\n                ]\n            ]\n\n            // When\n            let URLRequest = try encoding.CLDN_Encode(self.urlRequest, with: parameters)\n\n            // Then\n            XCTAssertNil(URLRequest.url?.query)\n            XCTAssertNotNil(URLRequest.value(forHTTPHeaderField: \"Content-Type\"))\n            XCTAssertEqual(URLRequest.value(forHTTPHeaderField: \"Content-Type\"), \"application/json\")\n            XCTAssertNotNil(URLRequest.httpBody)\n\n            if let httpBody = URLRequest.httpBody {\n                do {\n                    let json = try JSONSerialization.jsonObject(with: httpBody, options: .allowFragments)\n\n                    if let json = json as? NSObject {\n                        XCTAssertEqual(json, parameters as NSObject)\n                    } else {\n                        XCTFail(\"json should be an NSObject\")\n                    }\n                } catch {\n                    XCTFail(\"json should not be nil\")\n                }\n            }\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testJSONParameterEncodeArray() {\n        do {\n            // Given\n            let array: [String] = [\"foo\", \"bar\", \"baz\"]\n\n            // When\n            let URLRequest = try encoding.encode(self.urlRequest, withJSONObject: array)\n\n            // Then\n            XCTAssertNil(URLRequest.url?.query)\n            XCTAssertNotNil(URLRequest.value(forHTTPHeaderField: \"Content-Type\"))\n            XCTAssertEqual(URLRequest.value(forHTTPHeaderField: \"Content-Type\"), \"application/json\")\n            XCTAssertNotNil(URLRequest.httpBody)\n\n            if let httpBody = URLRequest.httpBody {\n                do {\n                    let json = try JSONSerialization.jsonObject(with: httpBody, options: .allowFragments)\n\n                    if let json = json as? NSObject {\n                        XCTAssertEqual(json, array as NSObject)\n                    } else {\n                        XCTFail(\"json should be an NSObject\")\n                    }\n                } catch {\n                    XCTFail(\"json should not be nil\")\n                }\n            }\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n\n    func testJSONParameterEncodeParametersRetainsCustomContentType() {\n        do {\n            // Given\n            var mutableURLRequest = URLRequest(url: URL(string: \"https://example.com/\")!)\n            mutableURLRequest.setValue(\"application/custom-json-type+json\", forHTTPHeaderField: \"Content-Type\")\n\n            let parameters = [\"foo\": \"bar\"]\n\n            // When\n            let urlRequest = try encoding.CLDN_Encode(mutableURLRequest, with: parameters)\n\n            // Then\n            XCTAssertNil(urlRequest.url?.query)\n            XCTAssertEqual(urlRequest.value(forHTTPHeaderField: \"Content-Type\"), \"application/custom-json-type+json\")\n        } catch {\n            XCTFail(\"Test encountered unexpected error: \\(error)\")\n        }\n    }\n}\n\n// MARK: -\n\nclass UploaderEncodingTestCase: ParameterEncodingTestCase {\n    func testUploadFolderDecouplingSimplifiedToRequest() throws {\n        let uploadRequestParams = CLDUploadRequestParams()\n        uploadRequestParams.setPublicIdPrefix(\"public_id_prefix\")\n        uploadRequestParams.setAssetFolder(\"asset_folder\")\n        uploadRequestParams.setDisplayName(\"display_name\")\n        uploadRequestParams.setUseFilenameAsDisplayName(true)\n        uploadRequestParams.setFolder(\"folder/test\")\n        try checkParamsEncodedCorrectly(params: uploadRequestParams.params)\n    }\n\n    func testRenameFolderDecouplingSimplifiedToRequest() throws {\n        var renameRequestParams = CLDRenameRequestParams(params: [\"asset_folder\": \"asset_folder\" as AnyObject, \"display_name\": \"display_name\"  as AnyObject, \"public_id_prefix\": \"public_id_prefix\"  as AnyObject])\n        try checkParamsEncodedCorrectly(params: renameRequestParams.params)\n    }\n\n    func testExplicityFolderDecouplingSimplifiedToRequest() throws {\n        let explicitRequestParams = CLDExplicitRequestParams()\n        explicitRequestParams.setPublicIdPrefix(\"public_id_prefix\")\n        explicitRequestParams.setAssetFolder(\"asset_folder\")\n        explicitRequestParams.setDisplayName(\"display_name\")\n        explicitRequestParams.setUseFilenameAsDisplayName(true)\n        explicitRequestParams.setFolder(\"folder/test\")\n        try checkParamsEncodedCorrectly(params: explicitRequestParams.params)\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Core/RequestTests.swift",
    "content": "//\n//  RequestTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass RequestInitializationTestCase: BaseTestCase {\n    func testRequestClassMethodWithMethodAndURL() {\n        // Given\n        let urlString = \"http://httpbin.org/\"\n\n        // When\n        let request = CLDNSessionManager.default.request(urlString)\n\n        // Then\n        XCTAssertNotNil(request.request)\n        XCTAssertEqual(request.request?.httpMethod, \"GET\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString)\n        XCTAssertNil(request.response)\n    }\n\n    func testRequestClassMethodWithMethodAndURLAndParameters() {\n        // Given\n        let urlString = \"http://httpbin.org/get\"\n\n        // When\n        let request = CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"])\n\n        // Then\n        XCTAssertNotNil(request.request)\n        XCTAssertEqual(request.request?.httpMethod, \"GET\")\n        XCTAssertNotEqual(request.request?.url?.absoluteString, urlString)\n        XCTAssertEqual(request.request?.url?.query, \"foo=bar\")\n        XCTAssertNil(request.response)\n    }\n\n    func testRequestClassMethodWithMethodURLParametersAndHeaders() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n        let headers = [\"Authorization\": \"123456\"]\n\n        // When\n        let request = CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"], headers: headers)\n\n        // Then\n        XCTAssertNotNil(request.request)\n        XCTAssertEqual(request.request?.httpMethod, \"GET\")\n        XCTAssertNotEqual(request.request?.url?.absoluteString, urlString)\n        XCTAssertEqual(request.request?.url?.query, \"foo=bar\")\n        XCTAssertEqual(request.request?.value(forHTTPHeaderField: \"Authorization\"), \"123456\")\n        XCTAssertNil(request.response)\n    }\n}\n\n// MARK: -\n\nclass RequestSubclassRequestPropertyTestCase: BaseTestCase {\n    private enum AuthenticationError: Error {\n        case expiredAccessToken\n    }\n\n    private class AuthenticationAdapter: CLDNRequestAdapter {\n        func CLDN_Adapt(_ urlRequest: URLRequest) throws -> URLRequest {\n            throw AuthenticationError.expiredAccessToken\n        }\n    }\n\n    private var sessionManager: CLDNSessionManager!\n\n    override func setUp() {\n        super.setUp()\n\n        sessionManager = CLDNSessionManager()\n        sessionManager.startRequestsImmediately = false\n\n        sessionManager.adapter = AuthenticationAdapter()\n    }\n\n    func testDataRequestHasURLRequest() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n\n        // When\n        let request = sessionManager.request(urlString)\n\n        // Then\n        XCTAssertNotNil(request.request)\n        XCTAssertEqual(request.request?.httpMethod, \"GET\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString)\n        XCTAssertNil(request.response)\n    }\n\n    func testUploadDataRequestHasURLRequest() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n\n        // When\n        let request = sessionManager.upload(Data(), to: urlString)\n\n        // Then\n        XCTAssertNotNil(request.request)\n        XCTAssertEqual(request.request?.httpMethod, \"POST\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString)\n        XCTAssertNil(request.response)\n    }\n\n    func testUploadFileRequestHasURLRequest() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n        let imageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n\n        // When\n        let request = sessionManager.upload(imageURL, to: urlString)\n\n        // Then\n        XCTAssertNotNil(request.request)\n        XCTAssertEqual(request.request?.httpMethod, \"POST\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString)\n        XCTAssertNil(request.response)\n    }\n\n    func testUploadStreamRequestHasURLRequest() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n        let imageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n        let imageStream = InputStream(url: imageURL)!\n\n        // When\n        let request = sessionManager.upload(imageStream, to: urlString)\n\n        // Then\n        XCTAssertNotNil(request.request)\n        XCTAssertEqual(request.request?.httpMethod, \"POST\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString)\n        XCTAssertNil(request.response)\n    }\n}\n\n// MARK: -\n\nclass RequestResponseTestCase: BaseTestCase {\n    func testRequestResponse() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n\n        let expectation = self.expectation(description: \"GET request should succeed: \\(urlString)\")\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"])\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n    }\n\n    func testRequestResponseWithProgress() {\n        // Given\n        let randomBytes = 4 * 1024 * 1024\n        let urlString = \"https://httpbin.org/bytes/\\(randomBytes)\"\n\n        let expectation = self.expectation(description: \"Bytes download progress should be reported: \\(urlString)\")\n\n        var progressValues: [Double] = []\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .downloadProgress { progress in\n                progressValues.append(progress.fractionCompleted)\n            }\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        var previousProgress: Double = progressValues.first ?? 0.0\n\n        for progress in progressValues {\n            XCTAssertGreaterThanOrEqual(progress, previousProgress)\n            previousProgress = progress\n        }\n\n        if let lastProgressValue = progressValues.last {\n            XCTAssertEqual(lastProgressValue, 1.0)\n        } else {\n            XCTFail(\"last item in progressValues should not be nil\")\n        }\n    }\n\n    func testRequestResponseWithStream() {\n        // Given\n        let randomBytes = 4 * 1024 * 1024\n        let urlString = \"https://httpbin.org/bytes/\\(randomBytes)\"\n\n        let expectation = self.expectation(description: \"Bytes download progress should be reported: \\(urlString)\")\n\n        var progressValues: [Double] = []\n        var accumulatedData = [Data]()\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .downloadProgress { progress in\n                progressValues.append(progress.fractionCompleted)\n            }\n            .stream { data in\n                accumulatedData.append(data)\n            }\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNil(response?.data)\n        XCTAssertNil(response?.error)\n        XCTAssertGreaterThanOrEqual(accumulatedData.count, 1)\n\n        var previousProgress: Double = progressValues.first ?? 0.0\n\n        for progress in progressValues {\n            XCTAssertGreaterThanOrEqual(progress, previousProgress)\n            previousProgress = progress\n        }\n\n        if let lastProgress = progressValues.last {\n            XCTAssertEqual(lastProgress, 1.0)\n        } else {\n            XCTFail(\"last item in progressValues should not be nil\")\n        }\n    }\n\n    func testPOSTRequestWithUnicodeParameters() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let parameters = [\n            \"french\": \"français\",\n            \"japanese\": \"日本語\",\n            \"arabic\": \"العربية\",\n            \"emoji\": \"😃\"\n        ]\n\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<Any>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, method: .post, parameters: parameters)\n            .responseJSON { closureResponse in\n                response = closureResponse\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        if let json = response?.result.value as? [String: Any], let form = json[\"form\"] as? [String: String] {\n            XCTAssertEqual(form[\"french\"], parameters[\"french\"])\n            XCTAssertEqual(form[\"japanese\"], parameters[\"japanese\"])\n            XCTAssertEqual(form[\"arabic\"], parameters[\"arabic\"])\n            XCTAssertEqual(form[\"emoji\"], parameters[\"emoji\"])\n        } else {\n            XCTFail(\"form parameter in JSON should not be nil\")\n        }\n    }\n\n    func testPOSTRequestWithBase64EncodedImages() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n\n        let pngBase64EncodedString: String = {\n            let URL = url(forResource: \"unicorn\", withExtension: \"png\")\n            let data = try! Data(contentsOf: URL)\n\n            return data.base64EncodedString(options: .lineLength64Characters)\n        }()\n\n        let jpegBase64EncodedString: String = {\n            let URL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n            let data = try! Data(contentsOf: URL)\n\n            return data.base64EncodedString(options: .lineLength64Characters)\n        }()\n\n        let parameters = [\n            \"email\": \"user@alamofire.org\",\n            \"png_image\": pngBase64EncodedString,\n            \"jpeg_image\": jpegBase64EncodedString\n        ]\n\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<Any>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, method: .post, parameters: parameters)\n            .responseJSON { closureResponse in\n                response = closureResponse\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n\n        if let json = response?.result.value as? [String: Any], let form = json[\"form\"] as? [String: String] {\n            XCTAssertEqual(form[\"email\"], parameters[\"email\"])\n            XCTAssertEqual(form[\"png_image\"], parameters[\"png_image\"])\n            XCTAssertEqual(form[\"jpeg_image\"], parameters[\"jpeg_image\"])\n        } else {\n            XCTFail(\"form parameter in JSON should not be nil\")\n        }\n    }\n}\n\n// MARK: -\n\nextension CLDNRequest {\n    fileprivate func preValidate(operation: @escaping () -> Void) -> Self {\n        delegate.queue.addOperation {\n            operation()\n        }\n\n        return self\n    }\n\n    fileprivate func postValidate(operation: @escaping () -> Void) -> Self {\n        delegate.queue.addOperation {\n            operation()\n        }\n\n        return self\n    }\n}\n\n// MARK: -\n\nclass RequestExtensionTestCase: BaseTestCase {\n    func testThatRequestExtensionHasAccessToTaskDelegateQueue() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n        let expectation = self.expectation(description: \"GET request should succeed: \\(urlString)\")\n\n        var responses: [String] = []\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .preValidate {\n                responses.append(\"preValidate\")\n            }\n            .validate()\n            .postValidate {\n                responses.append(\"postValidate\")\n            }\n            .response { _ in\n                responses.append(\"response\")\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        if responses.count == 3 {\n            XCTAssertEqual(responses[0], \"preValidate\")\n            XCTAssertEqual(responses[1], \"postValidate\")\n            XCTAssertEqual(responses[2], \"response\")\n        } else {\n            XCTFail(\"responses count should be equal to 3\")\n        }\n    }\n}\n\n// MARK: -\n\nclass RequestDescriptionTestCase: BaseTestCase {\n    func testRequestDescription() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n        let request = CLDNSessionManager.default.request(urlString)\n        let initialRequestDescription = request.description\n\n        let expectation = self.expectation(description: \"Request description should update: \\(urlString)\")\n\n        var finalRequestDescription: String?\n        var response: HTTPURLResponse?\n\n        // When\n        request.response { resp in\n            finalRequestDescription = request.description\n            response = resp.response\n\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertEqual(initialRequestDescription, \"GET https://httpbin.org/get\")\n        XCTAssertEqual(finalRequestDescription, \"GET https://httpbin.org/get (\\(response?.statusCode ?? -1))\")\n    }\n}\n\n// MARK: -\n\nclass RequestDebugDescriptionTestCase: BaseTestCase {\n    // MARK: Properties\n\n    let manager: CLDNSessionManager = {\n        let manager = CLDNSessionManager(configuration: .default)\n        manager.startRequestsImmediately = false\n        return manager\n    }()\n\n    let managerWithAcceptLanguageHeader: CLDNSessionManager = {\n        var headers = CLDNSessionManager.default.session.configuration.httpAdditionalHeaders ?? [:]\n        headers[\"Accept-Language\"] = \"en-US\"\n\n        let configuration = URLSessionConfiguration.default\n        configuration.httpAdditionalHeaders = headers\n\n        let manager = CLDNSessionManager(configuration: configuration)\n        manager.startRequestsImmediately = false\n\n        return manager\n    }()\n\n    let managerWithContentTypeHeader: CLDNSessionManager = {\n        var headers = CLDNSessionManager.default.session.configuration.httpAdditionalHeaders ?? [:]\n        headers[\"Content-Type\"] = \"application/json\"\n\n        let configuration = URLSessionConfiguration.default\n        configuration.httpAdditionalHeaders = headers\n\n        let manager = CLDNSessionManager(configuration: configuration)\n        manager.startRequestsImmediately = false\n\n        return manager\n    }()\n\n    let managerDisallowingCookies: CLDNSessionManager = {\n        let configuration = URLSessionConfiguration.default\n        configuration.httpShouldSetCookies = false\n\n        let manager = CLDNSessionManager(configuration: configuration)\n        manager.startRequestsImmediately = false\n\n        return manager\n    }()\n\n    // MARK: Tests\n\n    func testGETRequestDebugDescription() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n\n        // When\n        let request = manager.request(urlString)\n        let components = cURLCommandComponents(for: request)\n\n        // Then\n        XCTAssertEqual(components[0..<3], [\"$\", \"curl\", \"-v\"])\n        XCTAssertFalse(components.contains(\"-X\"))\n        XCTAssertEqual(components.last, \"\\\"\\(urlString)\\\"\")\n    }\n\n    func testGETRequestWithJSONHeaderDebugDescription() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n\n        // When\n        let headers: [String: String] = [ \"X-Custom-Header\": \"{\\\"key\\\": \\\"value\\\"}\" ]\n        let request = manager.request(urlString, headers: headers)\n\n        // Then\n        XCTAssertNotNil(request.debugDescription.range(of: \"-H \\\"X-Custom-Header: {\\\\\\\"key\\\\\\\": \\\\\\\"value\\\\\\\"}\\\"\"))\n    }\n\n    func testGETRequestWithDuplicateHeadersDebugDescription() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n\n        // When\n        let headers = [ \"Accept-Language\": \"en-GB\" ]\n        let request = managerWithAcceptLanguageHeader.request(urlString, headers: headers)\n        let components = cURLCommandComponents(for: request)\n\n        // Then\n        XCTAssertEqual(components[0..<3], [\"$\", \"curl\", \"-v\"])\n        XCTAssertFalse(components.contains(\"-X\"))\n        XCTAssertEqual(components.last, \"\\\"\\(urlString)\\\"\")\n\n        let tokens = request.debugDescription.components(separatedBy: \"Accept-Language:\")\n        XCTAssertTrue(tokens.count == 2, \"command should contain a single Accept-Language header\")\n\n        XCTAssertNotNil(request.debugDescription.range(of: \"-H \\\"Accept-Language: en-GB\\\"\"))\n    }\n\n    func testPOSTRequestDebugDescription() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n\n        // When\n        let request = manager.request(urlString, method: .post)\n        let components = cURLCommandComponents(for: request)\n\n        // Then\n        XCTAssertEqual(components[0..<3], [\"$\", \"curl\", \"-v\"])\n        XCTAssertEqual(components[3..<5], [\"-X\", \"POST\"])\n        XCTAssertEqual(components.last, \"\\\"\\(urlString)\\\"\")\n    }\n\n    func testPOSTRequestWithJSONParametersDebugDescription() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n\n        let parameters = [\n            \"foo\": \"bar\",\n            \"fo\\\"o\": \"b\\\"ar\",\n            \"f'oo\": \"ba'r\"\n        ]\n\n        // When\n        let request = manager.request(urlString, method: .post, parameters: parameters, encoding: CLDNJSONEncoding.default)\n        let components = cURLCommandComponents(for: request)\n\n        // Then\n        XCTAssertEqual(components[0..<3], [\"$\", \"curl\", \"-v\"])\n        XCTAssertEqual(components[3..<5], [\"-X\", \"POST\"])\n\n        XCTAssertNotNil(request.debugDescription.range(of: \"-H \\\"Content-Type: application/json\\\"\"))\n        XCTAssertNotNil(request.debugDescription.range(of: \"-d \\\"{\"))\n        XCTAssertNotNil(request.debugDescription.range(of: \"\\\\\\\"f'oo\\\\\\\":\\\\\\\"ba'r\\\\\\\"\"))\n        XCTAssertNotNil(request.debugDescription.range(of: \"\\\\\\\"fo\\\\\\\\\\\\\\\"o\\\\\\\":\\\\\\\"b\\\\\\\\\\\\\\\"ar\\\\\\\"\"))\n        XCTAssertNotNil(request.debugDescription.range(of: \"\\\\\\\"foo\\\\\\\":\\\\\\\"bar\\\\\"))\n\n        XCTAssertEqual(components.last, \"\\\"\\(urlString)\\\"\")\n    }\n\n    func testPOSTRequestWithCookieDebugDescription() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n\n        let properties = [\n            HTTPCookiePropertyKey.domain: \"httpbin.org\",\n            HTTPCookiePropertyKey.path: \"/post\",\n            HTTPCookiePropertyKey.name: \"foo\",\n            HTTPCookiePropertyKey.value: \"bar\",\n        ]\n\n        let cookie = HTTPCookie(properties: properties)!\n        manager.session.configuration.httpCookieStorage?.setCookie(cookie)\n\n        // When\n        let request = manager.request(urlString, method: .post)\n        let components = cURLCommandComponents(for: request)\n\n        // Then\n        XCTAssertEqual(components[0..<3], [\"$\", \"curl\", \"-v\"])\n        XCTAssertEqual(components[3..<5], [\"-X\", \"POST\"])\n        XCTAssertEqual(components.last, \"\\\"\\(urlString)\\\"\")\n        XCTAssertEqual(components[5..<6], [\"-b\"])\n    }\n\n    func testPOSTRequestWithCookiesDisabledDebugDescription() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n\n        let properties = [\n            HTTPCookiePropertyKey.domain: \"httpbin.org\",\n            HTTPCookiePropertyKey.path: \"/post\",\n            HTTPCookiePropertyKey.name: \"foo\",\n            HTTPCookiePropertyKey.value: \"bar\",\n        ]\n\n        let cookie = HTTPCookie(properties: properties)!\n        managerDisallowingCookies.session.configuration.httpCookieStorage?.setCookie(cookie)\n\n        // When\n        let request = managerDisallowingCookies.request(urlString, method: .post)\n        let components = cURLCommandComponents(for: request)\n\n        // Then\n        let cookieComponents = components.filter { $0 == \"-b\" }\n        XCTAssertTrue(cookieComponents.isEmpty)\n    }\n\n    func testMultipartFormDataRequestWithDuplicateHeadersDebugDescription() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let japaneseData = \"日本語\".data(using: .utf8, allowLossyConversion: false)!\n        let expectation = self.expectation(description: \"multipart form data encoding should succeed\")\n\n        var request: CLDNRequest?\n        var components: [String] = []\n\n        // When\n        managerWithContentTypeHeader.upload(\n            multipartFormData: { multipartFormData in\n                multipartFormData.append(japaneseData, withName: \"japanese\")\n            },\n            to: urlString,\n            encodingCompletion: { result in\n                switch result {\n                case .success(let upload, _, _):\n                    request = upload\n                    components = self.cURLCommandComponents(for: upload)\n\n                    expectation.fulfill()\n                case .failure:\n                    expectation.fulfill()\n                }\n            }\n        )\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        debugPrint(request!)\n\n        // Then\n        XCTAssertEqual(components[0..<3], [\"$\", \"curl\", \"-v\"])\n        XCTAssertTrue(components.contains(\"-X\"))\n        XCTAssertEqual(components.last, \"\\\"\\(urlString)\\\"\")\n\n        let tokens = request.debugDescription.components(separatedBy: \"Content-Type:\")\n        XCTAssertTrue(tokens.count == 2, \"command should contain a single Content-Type header\")\n\n        XCTAssertNotNil(request.debugDescription.range(of: \"-H \\\"Content-Type: multipart/form-data;\"))\n    }\n\n    func testThatRequestWithInvalidURLDebugDescription() {\n        // Given\n        let urlString = \"invalid_url\"\n\n        // When\n        let request = manager.request(urlString)\n        let debugDescription = request.debugDescription\n\n        // Then\n        XCTAssertNotNil(debugDescription, \"debugDescription should not crash\")\n    }\n\n    // MARK: Test Helper Methods\n\n    private func cURLCommandComponents(for request: CLDNRequest) -> [String] {\n        let whitespaceCharacterSet = CharacterSet.whitespacesAndNewlines\n        return request.debugDescription\n            .components(separatedBy: whitespaceCharacterSet)\n            .filter { $0 != \"\" && $0 != \"\\\\\" }\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Core/ResponseTests.swift",
    "content": "//\n//  ResponseTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass ResponseTestCase: BaseTestCase {\n    func testThatResponseReturnsSuccessResultWithValidData() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).response { resp in\n            response = resp\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func testThatResponseReturnsFailureResultWithOptionalDataAndError() {\n        // Given\n        let urlString = \"https://invalid-url-here.org/this/does/not/exist\"\n        let expectation = self.expectation(description: \"request should fail with 404\")\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).response { resp in\n            response = resp\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNotNil(response?.error)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n}\n\n// MARK: -\n\nclass ResponseDataTestCase: BaseTestCase {\n    func testThatResponseDataReturnsSuccessResultWithValidData() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<Data>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseData { resp in\n            response = resp\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func testThatResponseDataReturnsFailureResultWithOptionalDataAndError() {\n        // Given\n        let urlString = \"https://invalid-url-here.org/this/does/not/exist\"\n        let expectation = self.expectation(description: \"request should fail with 404\")\n\n        var response: CLDNDataResponse<Data>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseData { resp in\n            response = resp\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isFailure, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n}\n\n// MARK: -\n\nclass ResponseStringTestCase: BaseTestCase {\n    func testThatResponseStringReturnsSuccessResultWithValidString() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<String>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseString { resp in\n            response = resp\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func testThatResponseStringReturnsFailureResultWithOptionalDataAndError() {\n        // Given\n        let urlString = \"https://invalid-url-here.org/this/does/not/exist\"\n        let expectation = self.expectation(description: \"request should fail with 404\")\n\n        var response: CLDNDataResponse<String>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseString { resp in\n            response = resp\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isFailure, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n}\n\n// MARK: -\n\nclass ResponseJSONTestCase: BaseTestCase {\n    func testThatResponseJSONReturnsSuccessResultWithValidJSON() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<Any>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseJSON { resp in\n            response = resp\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func testThatResponseStringReturnsFailureResultWithOptionalDataAndError() {\n        // Given\n        let urlString = \"https://invalid-url-here.org/this/does/not/exist\"\n        let expectation = self.expectation(description: \"request should fail with 404\")\n\n        var response: CLDNDataResponse<Any>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseJSON { resp in\n            response = resp\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isFailure, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func skipped_testThatResponseJSONReturnsSuccessResultForGETRequest() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<Any>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseJSON { resp in\n            response = resp\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n\n        if\n            let responseDictionary = response?.result.value as? [String: Any],\n            let args = responseDictionary[\"args\"] as? [String: String]\n        {\n            XCTAssertEqual(args, [\"foo\": \"bar\"], \"args should match parameters\")\n        } else {\n            XCTFail(\"args should not be nil\")\n        }\n    }\n\n    func testThatResponseJSONReturnsSuccessResultForPOSTRequest() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<Any>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, method: .post, parameters: [\"foo\": \"bar\"]).responseJSON { resp in\n            response = resp\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n\n        if\n            let responseDictionary = response?.result.value as? [String: Any],\n            let form = responseDictionary[\"form\"] as? [String: String]\n        {\n            XCTAssertEqual(form, [\"foo\": \"bar\"], \"form should match parameters\")\n        } else {\n            XCTFail(\"form should not be nil\")\n        }\n    }\n}\n\n// MARK: -\n\nclass ResponseMapTestCase: BaseTestCase {\n    func skipped_testThatMapTransformsSuccessValue() {\n        // Given\n        let urlString = \"https://httpbin.org/header/foo\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<String>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseJSON { resp in\n            response = resp.flatMap { json in\n                // json[\"args\"][\"foo\"] is \"bar\": use this invariant to test the map function\n                return ((json as? [String: Any])?[\"args\"] as? [String: Any])?[\"foo\"] as? String ?? \"invalid\"\n            }\n\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n        XCTAssertEqual(response?.result.value, \"bar\")\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func testThatMapPreservesFailureError() {\n        // Given\n        let urlString = \"https://invalid-url-here.org/this/does/not/exist\"\n        let expectation = self.expectation(description: \"request should fail with 404\")\n\n        var response: CLDNDataResponse<String>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseData { resp in\n            response = resp.map { _ in \"ignored\" }\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isFailure, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n}\n\n// MARK: -\n\nclass ResponseFlatMapTestCase: BaseTestCase {\n    func skipped_testThatFlatMapTransformsSuccessValue() {\n        // Given\n        let urlString = \"https://httpbin.org/header/foo\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<String>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseJSON { resp in\n            response = resp.flatMap { json in\n                // json[\"args\"][\"foo\"] is \"bar\": use this invariant to test the flatMap function\n                return ((json as? [String: Any])?[\"args\"] as? [String: Any])?[\"foo\"] as? String ?? \"invalid\"\n            }\n\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n        XCTAssertEqual(response?.result.value, \"bar\")\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func testThatFlatMapCatchesTransformationError() {\n        // Given\n        struct TransformError: Error {}\n\n        let urlString = \"https://httpbin.org/get\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<String>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseData { resp in\n            response = resp.flatMap { json in\n                throw TransformError()\n            }\n\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isFailure, true)\n\n        if let error = response?.result.error {\n            XCTAssertTrue(error is TransformError)\n        } else {\n            XCTFail(\"flatMap should catch the transformation error\")\n        }\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func testThatFlatMapPreservesFailureError() {\n        // Given\n        let urlString = \"https://invalid-url-here.org/this/does/not/exist\"\n        let expectation = self.expectation(description: \"request should fail with 404\")\n\n        var response: CLDNDataResponse<String>?\n\n        // When\n        CLDNSessionManager.default.request(urlString, parameters: [\"foo\": \"bar\"]).responseData { resp in\n            response = resp.flatMap { _ in \"ignored\" }\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isFailure, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n}\n\n// MARK: -\n\nenum TestError: Error {\n    case error(error: Error)\n}\n\nenum TransformationError: Error {\n    case error\n\n    func alwaysFails() throws -> TestError {\n        throw TransformationError.error\n    }\n}\n\nclass ResponseMapErrorTestCase: BaseTestCase {\n    func testThatMapErrorTransformsFailureValue() {\n        // Given\n        let urlString = \"https://invalid-url-here.org/this/does/not/exist\"\n        let expectation = self.expectation(description: \"request should not succeed\")\n\n        var response: CLDNDataResponse<Any>?\n\n        // When\n        CLDNSessionManager.default.request(urlString).responseJSON { resp in\n            response = resp.mapError { error in\n                return TestError.error(error: error)\n            }\n\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isFailure, true)\n        guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func testThatMapErrorPreservesSuccessValue() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<Data>?\n\n        // When\n        CLDNSessionManager.default.request(urlString).responseData { resp in\n            response = resp.mapError { TestError.error(error: $0) }\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n}\n\n// MARK: -\n\nclass ResponseFlatMapErrorTestCase: BaseTestCase {\n    func testThatFlatMapErrorPreservesSuccessValue() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n        let expectation = self.expectation(description: \"request should succeed\")\n\n        var response: CLDNDataResponse<Data>?\n\n        // When\n        CLDNSessionManager.default.request(urlString).responseData { resp in\n            response = resp.flatMapError { TestError.error(error: $0) }\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func testThatFlatMapErrorCatchesTransformationError() {\n        // Given\n        let urlString = \"https://invalid-url-here.org/this/does/not/exist\"\n        let expectation = self.expectation(description: \"request should fail\")\n\n        var response: CLDNDataResponse<Data>?\n\n        // When\n        CLDNSessionManager.default.request(urlString).responseData { resp in\n            response = resp.flatMapError { _ in try TransformationError.error.alwaysFails() }\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isFailure, true)\n\n        if let error = response?.result.error {\n            XCTAssertTrue(error is TransformationError)\n        } else {\n            XCTFail(\"flatMapError should catch the transformation error\")\n        }\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n\n    func testThatFlatMapErrorTransformsError() {\n        // Given\n        let urlString = \"https://invalid-url-here.org/this/does/not/exist\"\n        let expectation = self.expectation(description: \"request should fail\")\n\n        var response: CLDNDataResponse<Data>?\n\n        // When\n        CLDNSessionManager.default.request(urlString).responseData { resp in\n            response = resp.flatMapError { TestError.error(error: $0) }\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isFailure, true)\n        guard let error = response?.error as? TestError, case .error = error else { XCTFail(); return }\n\n        var metrics: AnyObject? = nil\n        if #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) {\n            metrics = response?.metrics\n            XCTAssertNotNil(metrics)\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Core/ResultTests.swift",
    "content": "//\n//  ResultTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass ResultTestCase: BaseTestCase {\n    let error = CLDNError.responseValidationFailed(reason: .unacceptableStatusCode(code: 404))\n\n    // MARK: - Is Success Tests\n\n    func testThatIsSuccessPropertyReturnsTrueForSuccessCase() {\n        // Given, When\n        let result = CLDNResult<String>.success(\"success\")\n\n        // Then\n        XCTAssertTrue(result.isSuccess, \"result is success should be true for success case\")\n    }\n\n    func testThatIsSuccessPropertyReturnsFalseForFailureCase() {\n        // Given, When\n        let result = CLDNResult<String>.failure(error)\n\n        // Then\n        XCTAssertFalse(result.isSuccess, \"result is success should be false for failure case\")\n    }\n\n    // MARK: - Is Failure Tests\n\n    func testThatIsFailurePropertyReturnsFalseForSuccessCase() {\n        // Given, When\n        let result = CLDNResult<String>.success(\"success\")\n\n        // Then\n        XCTAssertFalse(result.isFailure, \"result is failure should be false for success case\")\n    }\n\n    func testThatIsFailurePropertyReturnsTrueForFailureCase() {\n        // Given, When\n        let result = CLDNResult<String>.failure(error)\n\n        // Then\n        XCTAssertTrue(result.isFailure, \"result is failure should be true for failure case\")\n    }\n\n    // MARK: - Value Tests\n\n    func testThatValuePropertyReturnsValueForSuccessCase() {\n        // Given, When\n        let result = CLDNResult<String>.success(\"success\")\n\n        // Then\n        XCTAssertEqual(result.value ?? \"\", \"success\", \"result value should match expected value\")\n    }\n\n    func testThatValuePropertyReturnsNilForFailureCase() {\n        // Given, When\n        let result = CLDNResult<String>.failure(error)\n\n        // Then\n        XCTAssertNil(result.value, \"result value should be nil for failure case\")\n    }\n\n    // MARK: - Error Tests\n\n    func testThatErrorPropertyReturnsNilForSuccessCase() {\n        // Given, When\n        let result = CLDNResult<String>.success(\"success\")\n\n        // Then\n        XCTAssertNil(result.error, \"result error should be nil for success case\")\n    }\n\n    func testThatErrorPropertyReturnsErrorForFailureCase() {\n        // Given, When\n        let result = CLDNResult<String>.failure(error)\n\n        // Then\n        XCTAssertNotNil(result.error, \"result error should not be nil for failure case\")\n    }\n\n    // MARK: - Description Tests\n\n    func testThatDescriptionStringMatchesExpectedValueForSuccessCase() {\n        // Given, When\n        let result = CLDNResult<String>.success(\"success\")\n\n        // Then\n        XCTAssertEqual(result.description, \"SUCCESS\", \"result description should match expected value for success case\")\n    }\n\n    func testThatDescriptionStringMatchesExpectedValueForFailureCase() {\n        // Given, When\n        let result = CLDNResult<String>.failure(error)\n\n        // Then\n        XCTAssertEqual(result.description, \"FAILURE\", \"result description should match expected value for failure case\")\n    }\n\n    // MARK: - Debug Description Tests\n\n    func testThatDebugDescriptionStringMatchesExpectedValueForSuccessCase() {\n        // Given, When\n        let result = CLDNResult<String>.success(\"success value\")\n\n        // Then\n        XCTAssertEqual(\n            result.debugDescription,\n            \"SUCCESS: success value\",\n            \"result debug description should match expected value for success case\"\n        )\n    }\n\n    func testThatDebugDescriptionStringMatchesExpectedValueForFailureCase() {\n        // Given, When\n        let result = CLDNResult<String>.failure(error)\n\n        // Then\n        XCTAssertEqual(\n            result.debugDescription,\n            \"FAILURE: \\(error)\",\n            \"result debug description should match expected value for failure case\"\n        )\n    }\n\n    // MARK: - Initializer Tests\n\n    func testThatInitializerFromThrowingClosureStoresResultAsASuccess() {\n        // Given\n        let value = \"success value\"\n\n        // When\n        let result1 = CLDNResult(value: { value })\n        let result2 = CLDNResult { value }\n\n        // Then\n        for result in [result1, result2] {\n            XCTAssertTrue(result.isSuccess)\n            XCTAssertEqual(result.value, value)\n        }\n    }\n\n    func testThatInitializerFromThrowingClosureCatchesErrorAsAFailure() {\n        // Given\n        struct ResultError: Error {}\n\n        // When\n        let result1 = CLDNResult(value: { throw ResultError() })\n        let result2 = CLDNResult { throw ResultError() }\n\n        // Then\n        for result in [result1, result2] {\n            XCTAssertTrue(result.isFailure)\n            XCTAssertTrue(result.error! is ResultError)\n        }\n    }\n\n    // MARK: - Unwrap Tests\n\n    func testThatUnwrapReturnsSuccessValue() {\n        // Given\n        let result = CLDNResult<String>.success(\"success value\")\n\n        // When\n        let unwrappedValue = try? result.unwrap()\n\n        // Then\n        XCTAssertEqual(unwrappedValue, \"success value\")\n    }\n\n    func testThatUnwrapThrowsFailureError() {\n        // Given\n        struct ResultError: Error {}\n\n        // When\n        let result = CLDNResult<String>.failure(ResultError())\n\n        // Then\n        do {\n            _ = try result.unwrap()\n            XCTFail(\"result unwrapping should throw the failure error\")\n        } catch {\n            XCTAssertTrue(error is ResultError)\n        }\n    }\n\n    // MARK: - Map Tests\n\n    func testThatMapTransformsSuccessValue() {\n        // Given\n        let result = CLDNResult<String>.success(\"success value\")\n\n        // When\n        #if swift(>=3.2)\n        let mappedResult = result.map { $0.count }\n        #else\n        let mappedResult = result.map { $0.characters.count }\n        #endif\n\n        // Then\n        XCTAssertEqual(mappedResult.value, 13)\n    }\n\n    func testThatMapPreservesFailureError() {\n        // Given\n        struct ResultError: Error {}\n        let result = CLDNResult<String>.failure(ResultError())\n\n        // When\n        #if swift(>=3.2)\n        let mappedResult = result.map { $0.count }\n        #else\n        let mappedResult = result.map { $0.characters.count }\n        #endif\n\n        // Then\n        if let error = mappedResult.error {\n            XCTAssertTrue(error is ResultError)\n        } else {\n            XCTFail(\"map should preserve the failure error\")\n        }\n    }\n\n    // MARK: - FlatMap Tests\n\n    func testThatFlatMapTransformsSuccessValue() {\n        // Given\n        let result = CLDNResult<String>.success(\"success value\")\n\n        // When\n        #if swift(>=3.2)\n        let mappedResult = result.map { $0.count }\n        #else\n        let mappedResult = result.map { $0.characters.count }\n        #endif\n\n        // Then\n        XCTAssertEqual(mappedResult.value, 13)\n    }\n\n    func testThatFlatMapCatchesTransformationError() {\n        // Given\n        struct TransformError: Error {}\n        let result = CLDNResult<String>.success(\"success value\")\n\n        // When\n        let mappedResult = result.flatMap { _ in throw TransformError() }\n\n        // Then\n        if let error = mappedResult.error {\n            XCTAssertTrue(error is TransformError)\n        } else {\n            XCTFail(\"flatMap should catch the transformation error\")\n        }\n    }\n\n    func testThatFlatMapPreservesFailureError() {\n        // Given\n        struct ResultError: Error {}\n        struct TransformError: Error {}\n        let result = CLDNResult<String>.failure(ResultError())\n\n        // When\n        let mappedResult = result.flatMap { _ in throw TransformError() }\n\n        // Then\n        if let error = mappedResult.error {\n            XCTAssertTrue(error is ResultError)\n        } else {\n            XCTFail(\"flatMap should preserve the failure error\")\n        }\n    }\n\n    // MARK: - Error Mapping Tests\n\n    func testMapErrorTransformsErrorValue() {\n        // Given\n        struct ResultError: Error {}\n        struct OtherError: Error { let error: Error }\n        let result: CLDNResult<String> = .failure(ResultError())\n\n        // When\n        let mappedResult = result.mapError { OtherError(error: $0) }\n\n        // Then\n        if let error = mappedResult.error {\n            XCTAssertTrue(error is OtherError)\n        } else {\n            XCTFail(\"mapError should transform error value\")\n        }\n    }\n\n    func testMapErrorPreservesSuccessError() {\n        // Given\n        struct ResultError: Error {}\n        struct OtherError: Error { let error: Error }\n        let result: CLDNResult<String> = .success(\"success\")\n\n        // When\n        let mappedResult = result.mapError { OtherError(error: $0) }\n\n        // Then\n        XCTAssertEqual(mappedResult.value, \"success\")\n    }\n\n    func testFlatMapErrorTransformsErrorValue() {\n        // Given\n        struct ResultError: Error {}\n        struct OtherError: Error { let error: Error }\n        let result: CLDNResult<String> = .failure(ResultError())\n\n        // When\n        let mappedResult = result.flatMapError { OtherError(error: $0) }\n\n        // Then\n        if let error = mappedResult.error {\n            XCTAssertTrue(error is OtherError)\n        } else {\n            XCTFail(\"mapError should transform error value\")\n        }\n    }\n\n    func testFlatMapErrorCapturesThrownError() {\n        // Given\n        struct ResultError: Error {}\n        struct OtherError: Error {\n            let error: Error\n            init(error: Error) throws { throw ThrownError() }\n        }\n        struct ThrownError: Error {}\n        let result: CLDNResult<String> = .failure(ResultError())\n\n        // When\n        let mappedResult = result.flatMapError { try OtherError(error: $0) }\n\n        // Then\n        if let error = mappedResult.error {\n            XCTAssertTrue(error is ThrownError)\n        } else {\n            XCTFail(\"mapError should capture thrown error value\")\n        }\n    }\n\n    // MARK: - With Value or Error Tests\n\n    func testWithValueExecutesWhenSuccess() {\n        // Given\n        let result: CLDNResult<String> = .success(\"success\")\n        var string = \"failure\"\n\n        // When\n        result.withValue { string = $0 }\n\n        // Then\n        XCTAssertEqual(string, \"success\")\n    }\n\n    func testWithValueDoesNotExecutesWhenFailure() {\n        // Given\n        struct ResultError: Error {}\n        let result: CLDNResult<String> = .failure(ResultError())\n        var string = \"failure\"\n\n        // When\n        result.withValue { string = $0 }\n\n        // Then\n        XCTAssertEqual(string, \"failure\")\n    }\n\n    func testWithErrorExecutesWhenFailure() {\n        // Given\n        struct ResultError: Error {}\n        let result: CLDNResult<String> = .failure(ResultError())\n        var string = \"success\"\n\n        // When\n        result.withError { string = \"\\(type(of: $0))\" }\n\n        // Then\n    #if swift(>=4.0)\n        XCTAssertEqual(string, \"ResultError\")\n    #elseif swift(>=3.2)\n        XCTAssertEqual(string, \"ResultError #1\")\n    #else\n        XCTAssertEqual(string, \"(ResultError #1)\")\n    #endif\n    }\n\n    func testWithErrorDoesNotExecuteWhenSuccess() {\n        // Given\n        let result: CLDNResult<String> = .success(\"success\")\n        var string = \"success\"\n\n        // When\n        result.withError { string = \"\\(type(of: $0))\" }\n\n        // Then\n        XCTAssertEqual(string, \"success\")\n    }\n\n    // MARK: - If Success or Failure Tests\n\n    func testIfSuccessExecutesWhenSuccess() {\n        // Given\n        let result: CLDNResult<String> = .success(\"success\")\n        var string = \"failure\"\n\n        // When\n        result.ifSuccess { string = \"success\" }\n\n        // Then\n        XCTAssertEqual(string, \"success\")\n    }\n\n    func testIfSuccessDoesNotExecutesWhenFailure() {\n        // Given\n        struct ResultError: Error {}\n        let result: CLDNResult<String> = .failure(ResultError())\n        var string = \"failure\"\n\n        // When\n        result.ifSuccess { string = \"success\" }\n\n        // Then\n        XCTAssertEqual(string, \"failure\")\n    }\n\n    func testIfFailureExecutesWhenFailure() {\n        // Given\n        struct ResultError: Error {}\n        let result: CLDNResult<String> = .failure(ResultError())\n        var string = \"success\"\n\n        // When\n        result.ifFailure { string = \"failure\" }\n\n        // Then\n        XCTAssertEqual(string, \"failure\")\n    }\n\n    func testIfFailureDoesNotExecuteWhenSuccess() {\n        // Given\n        let result: CLDNResult<String> = .success(\"success\")\n        var string = \"success\"\n\n        // When\n        result.ifFailure { string = \"failure\" }\n\n        // Then\n        XCTAssertEqual(string, \"success\")\n    }\n\n    // MARK: - Functional Chaining Tests\n\n    func testFunctionalMethodsCanBeChained() {\n        // Given\n        struct ResultError: Error {}\n        let result: CLDNResult<String> = .success(\"first\")\n        var string = \"first\"\n        var success = false\n\n        // When\n        let endResult = result\n            .map { _ in \"second\" }\n            .flatMap { _ in \"third\" }\n            .withValue { if $0 == \"third\" { string = \"fourth\" } }\n            .ifSuccess { success = true }\n\n        // Then\n        XCTAssertEqual(endResult.value, \"third\")\n        XCTAssertEqual(string, \"fourth\")\n        XCTAssertTrue(success)\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Core/SessionDelegateTests.swift",
    "content": "//\n//  SessionDelegateTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass SessionDelegateTestCase: BaseTestCase {\n\n    // prevents redundant call to redirect testing, currently there an issue with httpbin\n    // https://github.com/postmanlabs/httpbin/issues/617\n    lazy var allowDelegateTest: Bool = {\n        return ProcessInfo.processInfo.arguments.contains(\"TEST_REDIRECT\")\n    }()\n\n    var manager: CLDNSessionManager!\n\n    // MARK: - setup and teardown\n\n    override func setUp() {\n        super.setUp()\n        manager = CLDNSessionManager(configuration: .ephemeral)\n    }\n\n    // MARK: - Tests - Session Invalidation\n\n    func testThatSessionDidBecomeInvalidWithErrorClosureIsCalledWhenSet() {\n\n        // Given\n        let expectation = self.expectation(description: \"Override closure should be called\")\n\n        var overrideClosureCalled = false\n        var invalidationError: Error?\n\n        manager.delegate.sessionDidBecomeInvalidWithError = { _, error in\n            overrideClosureCalled = true\n            invalidationError = error\n\n            expectation.fulfill()\n        }\n\n        // When\n        manager.session.invalidateAndCancel()\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertTrue(overrideClosureCalled)\n        XCTAssertNil(invalidationError)\n    }\n\n    // MARK: - Tests - Session Challenges\n\n    func testThatSessionDidReceiveChallengeClosureIsCalledWhenSet() {\n        if #available(iOS 9.0, *) {\n            // Given\n            let expectation = self.expectation(description: \"Override closure should be called\")\n\n            var overrideClosureCalled = false\n            var response: HTTPURLResponse?\n\n            manager.delegate.sessionDidReceiveChallenge = { session, challenge in\n                overrideClosureCalled = true\n                return (.performDefaultHandling, nil)\n            }\n\n            // When\n            manager.request(\"https://httpbin.org/\").responseJSON { closureResponse in\n                response = closureResponse.response\n                expectation.fulfill()\n            }\n\n            waitForExpectations(timeout: timeout, handler: nil)\n\n            // Then\n            XCTAssertTrue(overrideClosureCalled)\n            XCTAssertEqual(response?.statusCode, 200)\n        } else {\n            // This test MUST be disabled on iOS 8.x because `respondsToSelector` is not being called for the\n            // `URLSession:didReceiveChallenge:completionHandler:` selector when more than one test here is run\n            // at a time. Whether we flush the URL session of wipe all the shared credentials, the behavior is\n            // still the same. Until we find a better solution, we'll need to disable this test on iOS 8.x.\n        }\n    }\n\n    func testThatSessionDidReceiveChallengeWithCompletionClosureIsCalledWhenSet() {\n        if #available(iOS 9.0, *) {\n            // Given\n            let expectation = self.expectation(description: \"Override closure should be called\")\n\n            var overrideClosureCalled = false\n            var response: HTTPURLResponse?\n\n            manager.delegate.sessionDidReceiveChallengeWithCompletion = { session, challenge, completion in\n                overrideClosureCalled = true\n                completion(.performDefaultHandling, nil)\n            }\n\n            // When\n            manager.request(\"https://httpbin.org/\").responseJSON { closureResponse in\n                response = closureResponse.response\n                expectation.fulfill()\n            }\n\n            waitForExpectations(timeout: timeout, handler: nil)\n\n            // Then\n            XCTAssertTrue(overrideClosureCalled)\n            XCTAssertEqual(response?.statusCode, 200)\n        } else {\n            // This test MUST be disabled on iOS 8.x because `respondsToSelector` is not being called for the\n            // `URLSession:didReceiveChallenge:completionHandler:` selector when more than one test here is run\n            // at a time. Whether we flush the URL session of wipe all the shared credentials, the behavior is\n            // still the same. Until we find a better solution, we'll need to disable this test on iOS 8.x.\n        }\n    }\n\n    // MARK: - Tests - Redirects\n\n    func testThatRequestWillPerformHTTPRedirectionByDefault() throws {\n\n        try XCTSkipUnless(allowDelegateTest, \"prevents the test from running, currently there's an issue with the remote server used\")\n\n        // Given\n        let redirectURLString = \"https://www.apple.com/\"\n        let urlString = \"https://httpbin.org/redirect-to?url=\\(redirectURLString)\"\n\n        let expectation = self.expectation(description: \"Request should redirect to \\(redirectURLString)\")\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        XCTAssertEqual(response?.response?.url?.absoluteString, redirectURLString)\n        XCTAssertEqual(response?.response?.statusCode, 200)\n    }\n\n    func testThatRequestWillPerformRedirectionMultipleTimesByDefault() throws {\n\n        try XCTSkipUnless(allowDelegateTest, \"prevents the test from running, currently there's an issue with the remote server used\")\n\n        // Given\n        let redirectURLString = \"https://httpbin.org/get\"\n        let urlString = \"https://httpbin.org/redirect/5\"\n\n        let expectation = self.expectation(description: \"Request should redirect to \\(redirectURLString)\")\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        XCTAssertEqual(response?.response?.url?.absoluteString, redirectURLString)\n        XCTAssertEqual(response?.response?.statusCode, 200)\n    }\n\n    func testThatTaskOverrideClosureCanPerformHTTPRedirection() throws {\n\n        try XCTSkipUnless(allowDelegateTest, \"prevents the test from running, currently there's an issue with the remote server used\")\n\n        // Given\n        let redirectURLString = \"https://www.apple.com/\"\n        let urlString = \"https://httpbin.org/redirect-to?url=\\(redirectURLString)\"\n\n        let expectation = self.expectation(description: \"Request should redirect to \\(redirectURLString)\")\n        let callbackExpectation = self.expectation(description: \"Redirect callback should be made\")\n        let delegate: CLDNSessionDelegate = manager.delegate\n\n        delegate.taskWillPerformHTTPRedirection = { _, _, _, request in\n            callbackExpectation.fulfill()\n            return request\n        }\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        XCTAssertEqual(response?.response?.url?.absoluteString, redirectURLString)\n        XCTAssertEqual(response?.response?.statusCode, 200)\n    }\n\n    func testThatTaskOverrideClosureWithCompletionCanPerformHTTPRedirection() throws {\n\n        try XCTSkipUnless(allowDelegateTest, \"prevents the test from running, currently there's an issue with the remote server used\")\n\n        // Given\n        let redirectURLString = \"https://www.apple.com/\"\n        let urlString = \"https://httpbin.org/redirect-to?url=\\(redirectURLString)\"\n\n        let expectation = self.expectation(description: \"Request should redirect to \\(redirectURLString)\")\n        let callbackExpectation = self.expectation(description: \"Redirect callback should be made\")\n        let delegate: CLDNSessionDelegate = manager.delegate\n\n        delegate.taskWillPerformHTTPRedirectionWithCompletion = { _, _, _, request, completion in\n            completion(request)\n            callbackExpectation.fulfill()\n        }\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        XCTAssertEqual(response?.response?.url?.absoluteString, redirectURLString)\n        XCTAssertEqual(response?.response?.statusCode, 200)\n    }\n\n    func testThatTaskOverrideClosureCanCancelHTTPRedirection() throws {\n\n        try XCTSkipUnless(allowDelegateTest, \"prevents the test from running, currently there's an issue with the remote server used\")\n\n        // Given\n        let redirectURLString = \"https://www.apple.com\"\n        let urlString = \"https://httpbin.org/redirect-to?url=\\(redirectURLString)\"\n\n        let expectation = self.expectation(description: \"Request should not redirect to \\(redirectURLString)\")\n        let callbackExpectation = self.expectation(description: \"Redirect callback should be made\")\n        let delegate: CLDNSessionDelegate = manager.delegate\n\n        delegate.taskWillPerformHTTPRedirectionWithCompletion = { _, _, _, _, completion in\n            callbackExpectation.fulfill()\n            completion(nil)\n        }\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        XCTAssertEqual(response?.response?.url?.absoluteString, urlString)\n        XCTAssertEqual(response?.response?.statusCode, 302)\n    }\n\n    func testThatTaskOverrideClosureWithCompletionCanCancelHTTPRedirection() throws {\n\n        try XCTSkipUnless(allowDelegateTest, \"prevents the test from running, currently there's an issue with the remote server used\")\n\n        // Given\n        let redirectURLString = \"https://www.apple.com\"\n        let urlString = \"https://httpbin.org/redirect-to?url=\\(redirectURLString)\"\n\n        let expectation = self.expectation(description: \"Request should not redirect to \\(redirectURLString)\")\n        let callbackExpectation = self.expectation(description: \"Redirect callback should be made\")\n        let delegate: CLDNSessionDelegate = manager.delegate\n\n        delegate.taskWillPerformHTTPRedirection = { _, _, _, _ in\n            callbackExpectation.fulfill()\n            return nil\n        }\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        XCTAssertEqual(response?.response?.url?.absoluteString, urlString)\n        XCTAssertEqual(response?.response?.statusCode, 302)\n    }\n\n    func testThatTaskOverrideClosureIsCalledMultipleTimesForMultipleHTTPRedirects() throws {\n\n        try XCTSkipUnless(allowDelegateTest, \"prevents the test from running, currently there's an issue with the remote server used\")\n\n        // Given\n        let redirectCount = 5\n        let redirectURLString = \"https://httpbin.org/get\"\n        let urlString = \"https://httpbin.org/redirect/\\(redirectCount)\"\n\n        let expectation = self.expectation(description: \"Request should redirect to \\(redirectURLString)\")\n        let delegate: CLDNSessionDelegate = manager.delegate\n        var redirectExpectations = [XCTestExpectation]()\n        for index in 0..<redirectCount {\n            redirectExpectations.insert(self.expectation(description: \"Redirect #\\(index) callback was received\"), at: 0)\n        }\n\n        delegate.taskWillPerformHTTPRedirection = { _, _, _, request in\n            if let redirectExpectation = redirectExpectations.popLast() {\n                redirectExpectation.fulfill()\n            } else {\n                XCTFail(\"Too many redirect callbacks were received\")\n            }\n\n            return request\n        }\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        XCTAssertEqual(response?.response?.url?.absoluteString, redirectURLString)\n        XCTAssertEqual(response?.response?.statusCode, 200)\n    }\n\n    func testThatTaskOverrideClosureWithCompletionIsCalledMultipleTimesForMultipleHTTPRedirects() throws {\n\n        try XCTSkipUnless(allowDelegateTest, \"prevents the test from running, currently there's an issue with the remote server used\")\n\n        // Given\n        let redirectCount = 5\n        let redirectURLString = \"https://httpbin.org/get\"\n        let urlString = \"https://httpbin.org/redirect/\\(redirectCount)\"\n\n        let expectation = self.expectation(description: \"Request should redirect to \\(redirectURLString)\")\n        let delegate: CLDNSessionDelegate = manager.delegate\n\n        var redirectExpectations = [XCTestExpectation]()\n\n        for index in 0..<redirectCount {\n            redirectExpectations.insert(self.expectation(description: \"Redirect #\\(index) callback was received\"), at: 0)\n        }\n\n        delegate.taskWillPerformHTTPRedirectionWithCompletion = { _, _, _, request, completion in\n            if let redirectExpectation = redirectExpectations.popLast() {\n                redirectExpectation.fulfill()\n            } else {\n                XCTFail(\"Too many redirect callbacks were received\")\n            }\n\n            completion(request)\n        }\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        XCTAssertEqual(response?.response?.url?.absoluteString, redirectURLString)\n        XCTAssertEqual(response?.response?.statusCode, 200)\n    }\n\n    func testThatRedirectedRequestContainsAllHeadersFromOriginalRequest() throws {\n\n        try XCTSkipUnless(allowDelegateTest, \"prevents the test from running, currently there's an issue with the remote server used\")\n\n        // Given\n        let redirectURLString = \"https://httpbin.org/get\"\n        let urlString = \"https://httpbin.org/redirect-to?url=\\(redirectURLString)\"\n        let headers = [\n            \"Authorization\": \"1234\",\n            \"Custom-Header\": \"foobar\",\n        ]\n\n        // NOTE: It appears that most headers are maintained during a redirect with the exception of the `Authorization`\n        // header. It appears that Apple's strips the `Authorization` header from the redirected URL request. If you\n        // need to maintain the `Authorization` header, you need to manually append it to the redirected request.\n\n        manager.delegate.taskWillPerformHTTPRedirection = { session, task, response, request in\n            var redirectedRequest = request\n\n            if\n                let originalRequest = task.originalRequest,\n                let headers = originalRequest.allHTTPHeaderFields,\n                let authorizationHeaderValue = headers[\"Authorization\"]\n            {\n                var mutableRequest = request\n                mutableRequest.setValue(authorizationHeaderValue, forHTTPHeaderField: \"Authorization\")\n                redirectedRequest = mutableRequest\n            }\n\n            return redirectedRequest\n        }\n\n        let expectation = self.expectation(description: \"Request should redirect to \\(redirectURLString)\")\n\n        var response: CLDNDataResponse<Any>?\n\n        // When\n        manager.request(urlString, headers: headers)\n            .responseJSON { closureResponse in\n                response = closureResponse\n                expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.result.isSuccess, true)\n\n        if let json = response?.result.value as? [String: Any], let headers = json[\"headers\"] as? [String: String] {\n            XCTAssertEqual(headers[\"Authorization\"], \"1234\")\n            XCTAssertEqual(headers[\"Custom-Header\"], \"foobar\")\n        }\n    }\n\n    // MARK: - Tests - Data Task Responses\n\n    func testThatDataTaskDidReceiveResponseClosureIsCalledWhenSet() {\n        // Given\n        let expectation = self.expectation(description: \"Override closure should be called\")\n\n        var overrideClosureCalled = false\n        var response: HTTPURLResponse?\n\n        manager.delegate.dataTaskDidReceiveResponse = { session, task, response in\n            overrideClosureCalled = true\n            return .allow\n        }\n\n        // When\n        manager.request(\"https://httpbin.org/\").responseJSON { closureResponse in\n            response = closureResponse.response\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertTrue(overrideClosureCalled)\n        XCTAssertEqual(response?.statusCode, 200)\n    }\n\n    func testThatDataTaskDidReceiveResponseWithCompletionClosureIsCalledWhenSet() {\n        // Given\n        let expectation = self.expectation(description: \"Override closure should be called\")\n\n        var overrideClosureCalled = false\n        var response: HTTPURLResponse?\n\n        manager.delegate.dataTaskDidReceiveResponseWithCompletion = { session, task, response, completion in\n            overrideClosureCalled = true\n            completion(.allow)\n        }\n\n        // When\n        manager.request(\"https://httpbin.org/\").responseJSON { closureResponse in\n            response = closureResponse.response\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertTrue(overrideClosureCalled)\n        XCTAssertEqual(response?.statusCode, 200)\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Core/SessionManagerTests.swift",
    "content": "//\n//  SessionManagerTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass SessionManagerTestCase: BaseTestCase {\n    \n    // MARK: Helper Types\n    \n    private class HTTPMethodAdapter: CLDNRequestAdapter {\n        let method: CLDNHTTPMethod\n        let throwsError: Bool\n        \n        init(method: CLDNHTTPMethod, throwsError: Bool = false) {\n            self.method = method\n            self.throwsError = throwsError\n        }\n        \n        func CLDN_Adapt(_ urlRequest: URLRequest) throws -> URLRequest {\n            guard !throwsError else { throw CLDNError.invalidURL(url: \"\") }\n            \n            var urlRequest = urlRequest\n            urlRequest.httpMethod = method.rawValue\n            \n            return urlRequest\n        }\n    }\n    \n    private class RequestHandler: CLDNRequestAdapter, CLDNRequestRetrier {\n        var adaptedCount = 0\n        var retryCount = 0\n        var retryErrors: [Error] = []\n        \n        var shouldApplyAuthorizationHeader = false\n        var throwsErrorOnSecondAdapt = false\n        \n        func CLDN_Adapt(_ urlRequest: URLRequest) throws -> URLRequest {\n            if throwsErrorOnSecondAdapt && adaptedCount == 1 {\n                throwsErrorOnSecondAdapt = false\n                throw CLDNError.invalidURL(url: \"\")\n            }\n            \n            var urlRequest = urlRequest\n            \n            adaptedCount += 1\n            \n            if shouldApplyAuthorizationHeader && adaptedCount > 1 {\n                if let header = CLDNRequest.authorizationHeader(user: \"user\", password: \"password\") {\n                    urlRequest.setValue(header.value, forHTTPHeaderField: header.key)\n                }\n            }\n            \n            return urlRequest\n        }\n        \n        func CLDN_Should(_ manager: CLDNSessionManager, retry request: CLDNRequest, with error: Error, completion: @escaping CLDNRequestRetryCompletion) {\n            retryCount += 1\n            retryErrors.append(error)\n            \n            if retryCount < 2 {\n                completion(true, 0.0)\n            } else {\n                completion(false, 0.0)\n            }\n        }\n    }\n    \n    private class UploadHandler: CLDNRequestAdapter, CLDNRequestRetrier {\n        var adaptedCount = 0\n        var retryCount = 0\n        var retryErrors: [Error] = []\n        \n        func CLDN_Adapt(_ urlRequest: URLRequest) throws -> URLRequest {\n            adaptedCount += 1\n            \n            if adaptedCount == 1 { throw CLDNError.invalidURL(url: \"\") }\n            \n            return urlRequest\n        }\n        \n        func CLDN_Should(_ manager: CLDNSessionManager, retry request: CLDNRequest, with error: Error, completion: @escaping CLDNRequestRetryCompletion) {\n            retryCount += 1\n            retryErrors.append(error)\n            \n            completion(true, 0.0)\n        }\n    }\n    \n    // prevents the test from running, currently there's an issue when Travis CI runs this test\n    lazy var allowManagerTest: Bool = {\n        return ProcessInfo.processInfo.arguments.contains(\"TEST_SESSION_MANAGER\")\n    }()\n    \n    // MARK: Tests - Initialization\n    \n    func testInitializerWithDefaultArguments() {\n        // Given, When\n        let manager = CLDNSessionManager()\n        \n        // Then\n        XCTAssertNotNil(manager.session.delegate, \"session delegate should not be nil\")\n        XCTAssertTrue(manager.delegate === manager.session.delegate, \"manager delegate should equal session delegate\")\n    }\n    \n    func testInitializerWithSpecifiedArguments() {\n        // Given\n        let configuration = URLSessionConfiguration.default\n        let delegate = CLDNSessionDelegate()\n        \n        \n        // When\n        let manager = CLDNSessionManager(\n            configuration: configuration,\n            delegate: delegate)\n        \n        // Then\n        XCTAssertNotNil(manager.session.delegate, \"session delegate should not be nil\")\n        XCTAssertTrue(manager.delegate === manager.session.delegate, \"manager delegate should equal session delegate\")\n    }\n    \n    func testThatFailableInitializerSucceedsWithDefaultArguments() {\n        // Given\n        let delegate = CLDNSessionDelegate()\n        let session: URLSession = {\n            let configuration = URLSessionConfiguration.default\n            return URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)\n        }()\n        \n        // When\n        let manager = CLDNSessionManager(session: session, delegate: delegate)\n        \n        // Then\n        if let manager = manager {\n            XCTAssertTrue(manager.delegate === manager.session.delegate, \"manager delegate should equal session delegate\")\n        } else {\n            XCTFail(\"manager should not be nil\")\n        }\n    }\n    \n    func testThatFailableInitializerSucceedsWithSpecifiedArguments() {\n        // Given\n        let delegate = CLDNSessionDelegate()\n        let session: URLSession = {\n            let configuration = URLSessionConfiguration.default\n            return URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)\n        }()\n        \n        // When\n        let manager = CLDNSessionManager(session: session, delegate: delegate)\n        \n        // Then\n        if let manager = manager {\n            XCTAssertTrue(manager.delegate === manager.session.delegate, \"manager delegate should equal session delegate\")\n        } else {\n            XCTFail(\"manager should not be nil\")\n        }\n    }\n    \n    func testThatFailableInitializerFailsWithWhenDelegateDoesNotEqualSessionDelegate() {\n        // Given\n        let delegate = CLDNSessionDelegate()\n        let session: URLSession = {\n            let configuration = URLSessionConfiguration.default\n            return URLSession(configuration: configuration, delegate: CLDNSessionDelegate(), delegateQueue: nil)\n        }()\n        \n        // When\n        let manager = CLDNSessionManager(session: session, delegate: delegate)\n        \n        // Then\n        XCTAssertNil(manager, \"manager should be nil\")\n    }\n    \n    func testThatFailableInitializerFailsWhenSessionDelegateIsNil() {\n        // Given\n        let delegate = CLDNSessionDelegate()\n        let session: URLSession = {\n            let configuration = URLSessionConfiguration.default\n            return URLSession(configuration: configuration, delegate: nil, delegateQueue: nil)\n        }()\n        \n        // When\n        let manager = CLDNSessionManager(session: session, delegate: delegate)\n        \n        // Then\n        XCTAssertNil(manager, \"manager should be nil\")\n    }\n    \n    // MARK: Tests - Default HTTP Headers\n    \n    func testDefaultUserAgentHeader() {\n        // Given, When\n        let userAgent = CLDNSessionManager.defaultHTTPHeaders[\"User-Agent\"]\n        \n        // Then\n        let osNameVersion: String = {\n            let version = ProcessInfo.processInfo.operatingSystemVersion\n            let versionString = \"\\(version.majorVersion).\\(version.minorVersion).\\(version.patchVersion)\"\n            \n            let osName: String = {\n#if os(iOS)\n                return \"iOS\"\n#elseif os(watchOS)\n                return \"watchOS\"\n#elseif os(tvOS)\n                return \"tvOS\"\n#elseif os(macOS)\n                return \"OS X\"\n#elseif os(Linux)\n                return \"Linux\"\n#else\n                return \"Unknown\"\n#endif\n            }()\n            \n            return \"\\(osName) \\(versionString)\"\n        }()\n        \n        let cloudinaryVersion: String = {\n            guard\n                let afInfo = Bundle(for: CLDNSessionManager.self).infoDictionary,\n                let build = afInfo[\"CFBundleShortVersionString\"]\n            else { return \"Unknown\" }\n            \n            return \"Cloudinary/\\(build)\"\n        }()\n        let info = Bundle.main.infoDictionary\n        let executable = info?[kCFBundleExecutableKey as String] as? String ?? \"Unknown\"\n        let appVersion = info?[\"CFBundleShortVersionString\"] as? String ?? \"Unknown\"\n        \n        \n        XCTAssertTrue(userAgent?.contains(cloudinaryVersion) == true)\n        XCTAssertTrue(userAgent?.contains(osNameVersion) == true)\n        XCTAssertTrue(userAgent?.contains(\"\\(executable)/\\(appVersion)\") == true)\n    }\n    \n    // MARK: Tests - Start Requests Immediately\n    \n    func testSetStartRequestsImmediatelyToFalseAndResumeRequest() {\n        // Given\n        let manager = CLDNSessionManager()\n        manager.startRequestsImmediately = false\n        \n        let url = URL(string: \"https://httpbin.org/\")!\n        let urlRequest = URLRequest(url: url)\n        \n        let expectation = self.expectation(description: \"\\(url)\")\n        \n        var response: HTTPURLResponse?\n        \n        // When\n        manager.request(urlRequest)\n            .response { resp in\n                response = resp.response\n                expectation.fulfill()\n            }\n            .resume()\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNotNil(response, \"response should not be nil\")\n        XCTAssertTrue(response?.statusCode == 200, \"response status code should be 200\")\n    }\n    \n    // MARK: Tests - Deinitialization\n    \n    func testReleasingManagerWithPendingRequestDeinitializesSuccessfully() {\n        // Given\n        var manager: CLDNSessionManager? = CLDNSessionManager()\n        manager?.startRequestsImmediately = false\n        \n        let url = URL(string: \"https://httpbin.org/get\")!\n        let urlRequest = URLRequest(url: url)\n        \n        // When\n        let request = manager?.request(urlRequest)\n        manager = nil\n        \n        // Then\n        XCTAssertTrue(request?.task?.state == .suspended, \"request task state should be '.Suspended'\")\n        XCTAssertNil(manager, \"manager should be nil\")\n    }\n    \n    func testReleasingManagerWithPendingCanceledRequestDeinitializesSuccessfully() {\n        // Given\n        var manager: CLDNSessionManager? = CLDNSessionManager()\n        manager!.startRequestsImmediately = false\n        \n        let url = URL(string: \"https://httpbin.org/\")!\n        let urlRequest = URLRequest(url: url)\n        \n        // When\n        let request = manager!.request(urlRequest)\n        request.cancel()\n        manager = nil\n        \n        // Then\n        let state = request.task?.state\n        XCTAssertTrue(state == .canceling || state == .completed, \"state should be .Canceling or .Completed\")\n        XCTAssertNil(manager, \"manager should be nil\")\n    }\n    \n    // MARK: Tests - Bad Requests\n    \n    func skipped_testThatDataRequestWithInvalidURLStringThrowsResponseHandlerError() {\n        // Given\n        let sessionManager = CLDNSessionManager()\n        let expectation = self.expectation(description: \"CLDNRequest should fail with error\")\n        \n        var response: CLDNDefaultDataResponse?\n        \n        // When\n        sessionManager.request(\"https://httpbin.org/get/äëïöü\").response { resp in\n            response = resp\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.data?.count, 0)\n        XCTAssertNotNil(response?.error)\n        \n        if let error = response?.error as? CLDNError {\n            XCTAssertTrue(error.isInvalidURLError)\n            XCTAssertEqual(error.urlConvertible as? String, \"https://httpbin.org/get/äëïöü\")\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n    \n    func skipped_testThatUploadDataRequestWithInvalidURLStringThrowsResponseHandlerError() {\n        // Given\n        let sessionManager = CLDNSessionManager()\n        let expectation = self.expectation(description: \"Upload should fail with error\")\n        \n        var response: CLDNDefaultDataResponse?\n        \n        // When\n        sessionManager.upload(Data(), to: \"https://httpbin.org/\").response { resp in\n            response = resp\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.data?.count, 0)\n        XCTAssertNotNil(response?.error)\n        \n        if let error = response?.error as? CLDNError {\n            XCTAssertTrue(error.isInvalidURLError)\n            XCTAssertEqual(error.urlConvertible as? String, \"https://httpbin.org/get/äëïöü\")\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n    \n    func skipped_testThatUploadFileRequestWithInvalidURLStringThrowsResponseHandlerError() {\n        // Given\n        let sessionManager = CLDNSessionManager()\n        let expectation = self.expectation(description: \"Upload should fail with error\")\n        \n        var response: CLDNDefaultDataResponse?\n        \n        // When\n        sessionManager.upload(URL(fileURLWithPath: \"/invalid\"), to: \"https://httpbin.org/get/äëïöü\").response { resp in\n            response = resp\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.data?.count, 0)\n        XCTAssertNotNil(response?.error)\n        \n        if let error = response?.error as? CLDNError {\n            XCTAssertTrue(error.isInvalidURLError)\n            XCTAssertEqual(error.urlConvertible as? String, \"https://httpbin.org/get/äëïöü\")\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n    \n    func skipped_testThatUploadStreamRequestWithInvalidURLStringThrowsResponseHandlerError() {\n        // Given\n        let sessionManager = CLDNSessionManager()\n        let expectation = self.expectation(description: \"Upload should fail with error\")\n        \n        var response: CLDNDefaultDataResponse?\n        \n        // When\n        sessionManager.upload(InputStream(data: Data()), to: \"https://httpbin.org/get/äëïöü\").response { resp in\n            response = resp\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNil(response?.request)\n        XCTAssertNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertEqual(response?.data?.count, 0)\n        XCTAssertNotNil(response?.error)\n        \n        if let error = response?.error as? CLDNError {\n            XCTAssertTrue(error.isInvalidURLError)\n            XCTAssertEqual(error.urlConvertible as? String, \"https://httpbin.org/get/äëïöü\")\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n    \n    // MARK: Tests - CLDNRequest Adapter\n    \n    func testThatSessionManagerCallsRequestAdapterWhenCreatingDataRequest() {\n        // Given\n        let adapter = HTTPMethodAdapter(method: .post)\n        \n        let sessionManager = CLDNSessionManager()\n        sessionManager.adapter = adapter\n        sessionManager.startRequestsImmediately = false\n        \n        // When\n        let request = sessionManager.request(\"https://httpbin.org/get\")\n        \n        // Then\n        XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)\n    }\n    \n    func testThatSessionManagerCallsRequestAdapterWhenCreatingUploadRequestWithData() {\n        // Given\n        let adapter = HTTPMethodAdapter(method: .get)\n        \n        let sessionManager = CLDNSessionManager()\n        sessionManager.adapter = adapter\n        sessionManager.startRequestsImmediately = false\n        \n        // When\n        let request = sessionManager.upload(\"data\".data(using: .utf8)!, to: \"https://httpbin.org/post\")\n        \n        // Then\n        XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)\n    }\n    \n    func testThatSessionManagerCallsRequestAdapterWhenCreatingUploadRequestWithFile() {\n        // Given\n        let adapter = HTTPMethodAdapter(method: .get)\n        \n        let sessionManager = CLDNSessionManager()\n        sessionManager.adapter = adapter\n        sessionManager.startRequestsImmediately = false\n        \n        // When\n        let fileURL = URL(fileURLWithPath: \"/path/to/some/file.txt\")\n        let request = sessionManager.upload(fileURL, to: \"https://httpbin.org/post\")\n        \n        // Then\n        XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)\n    }\n    \n    func testThatSessionManagerCallsRequestAdapterWhenCreatingUploadRequestWithInputStream() {\n        // Given\n        let adapter = HTTPMethodAdapter(method: .get)\n        \n        let sessionManager = CLDNSessionManager()\n        sessionManager.adapter = adapter\n        sessionManager.startRequestsImmediately = false\n        \n        // When\n        let inputStream = InputStream(data: \"data\".data(using: .utf8)!)\n        let request = sessionManager.upload(inputStream, to: \"https://httpbin.org/post\")\n        \n        // Then\n        XCTAssertEqual(request.task?.originalRequest?.httpMethod, adapter.method.rawValue)\n    }\n    \n    func testThatRequestAdapterErrorThrowsResponseHandlerError() {\n        // Given\n        let adapter = HTTPMethodAdapter(method: .post, throwsError: true)\n        \n        let sessionManager = CLDNSessionManager()\n        sessionManager.adapter = adapter\n        sessionManager.startRequestsImmediately = false\n        \n        // When\n        let request = sessionManager.request(\"https://httpbin.org/get\")\n        \n        // Then\n        if let error = request.delegate.error as? CLDNError {\n            XCTAssertTrue(error.isInvalidURLError)\n            XCTAssertEqual(error.urlConvertible as? String, \"\")\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n    \n    // MARK: Tests - CLDNRequest Retrier\n    \n    func testThatSessionManagerCallsRequestRetrierWhenRequestEncountersError() throws {\n        \n        try XCTSkipUnless(allowManagerTest, \"prevents the test from running, currently there's an issue when Travis CI runs this test\")\n        \n        // Given\n        let handler = RequestHandler()\n        \n        let sessionManager = CLDNSessionManager()\n        sessionManager.adapter = handler\n        sessionManager.retrier = handler\n        \n        let expectation = self.expectation(description: \"request should eventually fail\")\n        var response: CLDNDataResponse<Any>?\n        \n        // When\n        let request = sessionManager.request(\"https://httpbin.org/basic-auth/user/password\")\n            .validate()\n            .responseJSON { jsonResponse in\n                response = jsonResponse\n                expectation.fulfill()\n            }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertEqual(handler.adaptedCount, 2)\n        XCTAssertEqual(handler.retryCount, 2)\n        XCTAssertEqual(request.retryCount, 1)\n        XCTAssertEqual(response?.result.isSuccess, false)\n        XCTAssertTrue(sessionManager.delegate.requests.isEmpty)\n    }\n    \n    func testThatSessionManagerCallsRequestRetrierWhenRequestInitiallyEncountersAdaptError() throws {\n        \n        try XCTSkipUnless(allowManagerTest, \"prevents the test from running, currently there's an issue when Travis CI runs this test\")\n        \n        // Given\n        let handler = RequestHandler()\n        handler.adaptedCount = 1\n        handler.throwsErrorOnSecondAdapt = true\n        handler.shouldApplyAuthorizationHeader = true\n        \n        let sessionManager = CLDNSessionManager()\n        sessionManager.adapter = handler\n        sessionManager.retrier = handler\n        \n        let expectation = self.expectation(description: \"request should eventually fail\")\n        var response: CLDNDataResponse<Any>?\n        \n        // When\n        sessionManager.request(\"https://httpbin.org/basic-auth/user/password\")\n            .validate()\n            .responseJSON { jsonResponse in\n                response = jsonResponse\n                expectation.fulfill()\n            }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertEqual(handler.adaptedCount, 2, \"handler.adaptedCount should be equal to 2\")\n        XCTAssertEqual(handler.retryCount, 1, \"handler.retryCount should be equal to 1\")\n        XCTAssertEqual(response?.result.isSuccess, true, \"response?.result.isSuccess should be equal to true\")\n        XCTAssertTrue(sessionManager.delegate.requests.isEmpty, \"delegate.requests.isEmpty should be empty\")\n        \n        handler.retryErrors.forEach { XCTAssertFalse($0 is AdaptError, \"retry error should not be AdaptError\") }\n    }\n    \n    func testThatSessionManagerCallsRequestRetrierWhenUploadInitiallyEncountersAdaptError() throws {\n        \n        try XCTSkipUnless(allowManagerTest, \"prevents the test from running, currently there's an issue when Travis CI runs this test\")\n        \n        // Given\n        let handler = UploadHandler()\n        \n        let sessionManager = CLDNSessionManager()\n        sessionManager.adapter = handler\n        sessionManager.retrier = handler\n        \n        let expectation = self.expectation(description: \"request should eventually fail\")\n        var response: CLDNDataResponse<Any>?\n        \n        let uploadData = \"upload data\".data(using: .utf8, allowLossyConversion: false)!\n        \n        // When\n        sessionManager.upload(uploadData, to: \"https://httpbin.org/post\")\n            .validate()\n            .responseJSON { jsonResponse in\n                response = jsonResponse\n                expectation.fulfill()\n            }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertEqual(handler.adaptedCount, 2)\n        XCTAssertEqual(handler.retryCount, 1)\n        XCTAssertEqual(response?.result.isSuccess, true)\n        XCTAssertTrue(sessionManager.delegate.requests.isEmpty)\n        \n        handler.retryErrors.forEach { XCTAssertFalse($0 is AdaptError) }\n    }\n    \n    func testThatSessionManagerCallsAdapterWhenRequestIsRetried() throws {\n        \n        try XCTSkipUnless(allowManagerTest, \"prevents the test from running, currently there's an issue when Travis CI runs this test\")\n        \n        // Given\n        let handler = RequestHandler()\n        handler.shouldApplyAuthorizationHeader = true\n        \n        let sessionManager = CLDNSessionManager()\n        sessionManager.adapter = handler\n        sessionManager.retrier = handler\n        \n        let expectation = self.expectation(description: \"request should eventually fail\")\n        var response: CLDNDataResponse<Any>?\n        \n        // When\n        let request = sessionManager.request(\"https://httpbin.org/basic-auth/user/password\")\n            .validate()\n            .responseJSON { jsonResponse in\n                response = jsonResponse\n                expectation.fulfill()\n            }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertEqual(handler.adaptedCount, 2)\n        XCTAssertEqual(handler.retryCount, 1)\n        XCTAssertEqual(request.retryCount, 1)\n        XCTAssertEqual(response?.result.isSuccess, true)\n        XCTAssertTrue(sessionManager.delegate.requests.isEmpty)\n    }\n    \n    func testThatRequestAdapterErrorThrowsResponseHandlerErrorWhenRequestIsRetried() throws {\n        \n        try XCTSkipUnless(allowManagerTest, \"prevents the test from running, currently there's an issue when Travis CI runs this test\")\n        \n        // Given\n        let handler = RequestHandler()\n        handler.throwsErrorOnSecondAdapt = true\n        \n        let sessionManager = CLDNSessionManager()\n        sessionManager.adapter = handler\n        sessionManager.retrier = handler\n        \n        let expectation = self.expectation(description: \"request should eventually fail\")\n        var response: CLDNDataResponse<Any>?\n        \n        // When\n        let request = sessionManager.request(\"https://httpbin.org/basic-auth/user/password\")\n            .validate()\n            .responseJSON { jsonResponse in\n                response = jsonResponse\n                expectation.fulfill()\n            }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertEqual(handler.adaptedCount, 1, \"handler.adaptedCount count should be equal to 0\")\n        XCTAssertEqual(handler.retryCount, 1, \"handler.retry count should be equal to 0\")\n        XCTAssertEqual(request.retryCount, 0, \"result.retry count should be equal to 0\")\n        XCTAssertEqual(response?.result.isSuccess, false, \"result should succeed\")\n        XCTAssertTrue(sessionManager.delegate.requests.isEmpty, \"delegate.requests should be empty\")\n        \n        if let error = response?.result.error as? CLDNError {\n            XCTAssertTrue(error.isInvalidURLError, \"error.isInvalidURLError should be true\")\n            XCTAssertEqual(error.urlConvertible as? String, \"\", \"error.urlConvertible shold be true\")\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n}\n\n// MARK: -\n\nclass SessionManagerConfigurationHeadersTestCase: BaseTestCase {\n    enum ConfigurationType {\n        case `default`, ephemeral, background\n    }\n    \n    func testThatDefaultConfigurationHeadersAreSentWithRequest() {\n        // Given, When, Then\n        executeAuthorizationHeaderTest(for: .default)\n    }\n    \n    func testThatEphemeralConfigurationHeadersAreSentWithRequest() {\n        // Given, When, Then\n        executeAuthorizationHeaderTest(for: .ephemeral)\n    }\n#if os(macOS)\n    func testThatBackgroundConfigurationHeadersAreSentWithRequest() {\n        // Given, When, Then\n        executeAuthorizationHeaderTest(for: .background)\n    }\n#endif\n    \n    private func executeAuthorizationHeaderTest(for type: ConfigurationType) {\n        // Given\n        let manager: CLDNSessionManager = {\n            let configuration: URLSessionConfiguration = {\n                let configuration: URLSessionConfiguration\n                \n                switch type {\n                case .default:\n                    configuration = .default\n                case .ephemeral:\n                    configuration = .ephemeral\n                case .background:\n                    let identifier = \"org.cloudinary.test.manager-configuration-tests\"\n                    configuration = .background(withIdentifier: identifier)\n                }\n                \n                var headers = CLDNSessionManager.defaultHTTPHeaders\n                headers[\"Authorization\"] = \"Bearer 123456\"\n                configuration.httpAdditionalHeaders = headers\n                \n                return configuration\n            }()\n            \n            return CLDNSessionManager(configuration: configuration)\n        }()\n        \n        let expectation = self.expectation(description: \"request should complete successfully\")\n        \n        var response: CLDNDataResponse<Any>?\n        \n        // When\n        manager.request(\"https://httpbin.org/headers\")\n            .responseJSON { closureResponse in\n                response = closureResponse\n                expectation.fulfill()\n            }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        if let response = response {\n            XCTAssertNotNil(response.request, \"request should not be nil\")\n            XCTAssertNotNil(response.response, \"response should not be nil\")\n            XCTAssertNotNil(response.data, \"data should not be nil\")\n            XCTAssertTrue(response.result.isSuccess, \"result should be a success\")\n            \n            if\n                let response = response.result.value as? [String: Any],\n                let headers = response[\"headers\"] as? [String: String],\n                let authorization = headers[\"Authorization\"]\n            {\n                XCTAssertEqual(authorization, \"Bearer 123456\", \"authorization header value does not match\")\n            } else {\n                XCTFail(\"failed to extract authorization header value\")\n            }\n        } else {\n            XCTFail(\"response should not be nil\")\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Core/UploadTests.swift",
    "content": "//\n//  UploadTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass UploadFileInitializationTestCase: BaseTestCase {\n    func testUploadClassMethodWithMethodURLAndFile() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n        let imageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n\n        // When\n        let request = CLDNSessionManager.default.upload(imageURL, to: urlString)\n\n        // Then\n        XCTAssertNotNil(request.request, \"request should not be nil\")\n        XCTAssertEqual(request.request?.httpMethod ?? \"\", \"POST\", \"request HTTP method should be POST\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString, \"request URL string should be equal\")\n        XCTAssertNil(request.response, \"response should be nil\")\n    }\n\n    func testUploadClassMethodWithMethodURLHeadersAndFile() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n        let headers = [\"Authorization\": \"123456\"]\n        let imageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n\n        // When\n        let request = CLDNSessionManager.default.upload(imageURL, to: urlString, method: .post, headers: headers)\n\n        // Then\n        XCTAssertNotNil(request.request, \"request should not be nil\")\n        XCTAssertEqual(request.request?.httpMethod ?? \"\", \"POST\", \"request HTTP method should be POST\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString, \"request URL string should be equal\")\n\n        let authorizationHeader = request.request?.value(forHTTPHeaderField: \"Authorization\") ?? \"\"\n        XCTAssertEqual(authorizationHeader, \"123456\", \"Authorization header is incorrect\")\n\n        XCTAssertNil(request.response, \"response should be nil\")\n    }\n}\n\n// MARK: -\n\nclass UploadDataInitializationTestCase: BaseTestCase {\n    func testUploadClassMethodWithMethodURLAndData() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n\n        // When\n        let request = CLDNSessionManager.default.upload(Data(), to: urlString)\n\n        // Then\n        XCTAssertNotNil(request.request, \"request should not be nil\")\n        XCTAssertEqual(request.request?.httpMethod ?? \"\", \"POST\", \"request HTTP method should be POST\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString, \"request URL string should be equal\")\n        XCTAssertNil(request.response, \"response should be nil\")\n    }\n\n    func testUploadClassMethodWithMethodURLHeadersAndData() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n        let headers = [\"Authorization\": \"123456\"]\n\n        // When\n        let request = CLDNSessionManager.default.upload(Data(), to: urlString, headers: headers)\n\n        // Then\n        XCTAssertNotNil(request.request, \"request should not be nil\")\n        XCTAssertEqual(request.request?.httpMethod ?? \"\", \"POST\", \"request HTTP method should be POST\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString, \"request URL string should be equal\")\n\n        let authorizationHeader = request.request?.value(forHTTPHeaderField: \"Authorization\") ?? \"\"\n        XCTAssertEqual(authorizationHeader, \"123456\", \"Authorization header is incorrect\")\n\n        XCTAssertNil(request.response, \"response should be nil\")\n    }\n}\n\n// MARK: -\n\nclass UploadStreamInitializationTestCase: BaseTestCase {\n    func testUploadClassMethodWithMethodURLAndStream() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n        let imageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n        let imageStream = InputStream(url: imageURL)!\n\n        // When\n        let request = CLDNSessionManager.default.upload(imageStream, to: urlString)\n\n        // Then\n        XCTAssertNotNil(request.request, \"request should not be nil\")\n        XCTAssertEqual(request.request?.httpMethod ?? \"\", \"POST\", \"request HTTP method should be POST\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString, \"request URL string should be equal\")\n        XCTAssertNil(request.response, \"response should be nil\")\n    }\n\n    func testUploadClassMethodWithMethodURLHeadersAndStream() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n        let imageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n        let headers = [\"Authorization\": \"123456\"]\n        let imageStream = InputStream(url: imageURL)!\n\n        // When\n        let request = CLDNSessionManager.default.upload(imageStream, to: urlString, headers: headers)\n\n        // Then\n        XCTAssertNotNil(request.request, \"request should not be nil\")\n        XCTAssertEqual(request.request?.httpMethod ?? \"\", \"POST\", \"request HTTP method should be POST\")\n        XCTAssertEqual(request.request?.url?.absoluteString, urlString, \"request URL string should be equal\")\n\n        let authorizationHeader = request.request?.value(forHTTPHeaderField: \"Authorization\") ?? \"\"\n        XCTAssertEqual(authorizationHeader, \"123456\", \"Authorization header is incorrect\")\n\n        XCTAssertNil(request.response, \"response should be nil\")\n    }\n}\n\n// MARK: -\n\nclass UploadDataTestCase: BaseTestCase {\n    func testUploadDataRequest() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let data = \"Lorem ipsum dolor sit amet\".data(using: .utf8, allowLossyConversion: false)!\n\n        let expectation = self.expectation(description: \"Upload request should succeed: \\(urlString)\")\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        CLDNSessionManager.default.upload(data, to: urlString)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNil(response?.error)\n    }\n\n    func skipped_testUploadDataRequestWithProgress() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let data: Data = {\n            var text = \"\"\n            for _ in 1...3_000 {\n                text += \"Lorem ipsum dolor sit amet, consectetur adipiscing elit. \"\n            }\n\n            return text.data(using: .utf8, allowLossyConversion: false)!\n        }()\n\n        let expectation = self.expectation(description: \"Bytes upload progress should be reported: \\(urlString)\")\n\n        var uploadProgressValues: [Double] = []\n        var downloadProgressValues: [Double] = []\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        CLDNSessionManager.default.upload(data, to: urlString)\n            .uploadProgress { progress in\n                uploadProgressValues.append(progress.fractionCompleted)\n            }\n            .downloadProgress { progress in\n                downloadProgressValues.append(progress.fractionCompleted)\n            }\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        var previousUploadProgress: Double = uploadProgressValues.first ?? 0.0\n\n        for progress in uploadProgressValues {\n            XCTAssertGreaterThanOrEqual(progress, previousUploadProgress)\n            previousUploadProgress = progress\n        }\n\n        if let lastProgressValue = uploadProgressValues.last {\n            XCTAssertEqual(lastProgressValue, 1.0)\n        } else {\n            XCTFail(\"last item in uploadProgressValues should not be nil\")\n        }\n\n        var previousDownloadProgress: Double = downloadProgressValues.first ?? 0.0\n\n        for progress in downloadProgressValues {\n            XCTAssertGreaterThanOrEqual(progress, previousDownloadProgress)\n            previousDownloadProgress = progress\n        }\n\n        if let lastProgressValue = downloadProgressValues.last {\n            XCTAssertEqual(lastProgressValue, 1.0)\n        } else {\n            XCTFail(\"last item in downloadProgressValues should not be nil\")\n        }\n    }\n}\n\n// MARK: -\n\nclass UploadMultipartFormDataTestCase: BaseTestCase {\n\n    // MARK: Tests\n\n    func testThatUploadingMultipartFormDataSetsContentTypeHeader() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let uploadData = \"upload_data\".data(using: .utf8, allowLossyConversion: false)!\n\n        let expectation = self.expectation(description: \"multipart form data upload should succeed\")\n\n        var formData: CLDNMultipartFormData?\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        CLDNSessionManager.default.upload(\n            multipartFormData: { multipartFormData in\n                multipartFormData.append(uploadData, withName: \"upload_data\")\n                formData = multipartFormData\n            },\n            to: urlString,\n            encodingCompletion: { result in\n                switch result {\n                case .success(let upload, _, _):\n                    upload.response { resp in\n                        response = resp\n                        expectation.fulfill()\n                    }\n                case .failure:\n                    expectation.fulfill()\n                }\n            }\n        )\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        if\n            let request = response?.request,\n            let multipartFormData = formData,\n            let contentType = request.value(forHTTPHeaderField: \"Content-Type\")\n        {\n            XCTAssertEqual(contentType, multipartFormData.contentType)\n        } else {\n            XCTFail(\"Content-Type header value should not be nil\")\n        }\n    }\n\n    func testThatUploadingMultipartFormDataSucceedsWithDefaultParameters() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let frenchData = \"français\".data(using: .utf8, allowLossyConversion: false)!\n        let japaneseData = \"日本語\".data(using: .utf8, allowLossyConversion: false)!\n\n        let expectation = self.expectation(description: \"multipart form data upload should succeed\")\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        CLDNSessionManager.default.upload(\n            multipartFormData: { multipartFormData in\n                multipartFormData.append(frenchData, withName: \"french\")\n                multipartFormData.append(japaneseData, withName: \"japanese\")\n            },\n            to: urlString,\n            encodingCompletion: { result in\n                switch result {\n                case .success(let upload, _, _):\n                    upload.response { resp in\n                        response = resp\n                        expectation.fulfill()\n                    }\n                case .failure:\n                    expectation.fulfill()\n                }\n            }\n        )\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n    }\n\n    func testThatUploadingMultipartFormDataWhileStreamingFromMemoryMonitorsProgress() {\n        executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: false)\n    }\n\n    func testThatUploadingMultipartFormDataWhileStreamingFromDiskMonitorsProgress() {\n        executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: true)\n    }\n\n    func testThatUploadingMultipartFormDataBelowMemoryThresholdStreamsFromMemory() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let frenchData = \"français\".data(using: .utf8, allowLossyConversion: false)!\n        let japaneseData = \"日本語\".data(using: .utf8, allowLossyConversion: false)!\n\n        let expectation = self.expectation(description: \"multipart form data upload should succeed\")\n\n        var streamingFromDisk: Bool?\n        var streamFileURL: URL?\n\n        // When\n        CLDNSessionManager.default.upload(\n            multipartFormData: { multipartFormData in\n                multipartFormData.append(frenchData, withName: \"french\")\n                multipartFormData.append(japaneseData, withName: \"japanese\")\n            },\n            to: urlString,\n            encodingCompletion: { result in\n                switch result {\n                case let .success(upload, uploadStreamingFromDisk, uploadStreamFileURL):\n                    streamingFromDisk = uploadStreamingFromDisk\n                    streamFileURL = uploadStreamFileURL\n\n                    upload.response { _ in\n                        expectation.fulfill()\n                    }\n                case .failure:\n                    expectation.fulfill()\n                }\n            }\n        )\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(streamingFromDisk, \"streaming from disk should not be nil\")\n        XCTAssertNil(streamFileURL, \"stream file URL should be nil\")\n\n        if let streamingFromDisk = streamingFromDisk {\n            XCTAssertFalse(streamingFromDisk, \"streaming from disk should be false\")\n        }\n    }\n\n    func testThatUploadingMultipartFormDataBelowMemoryThresholdSetsContentTypeHeader() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let uploadData = \"upload data\".data(using: .utf8, allowLossyConversion: false)!\n\n        let expectation = self.expectation(description: \"multipart form data upload should succeed\")\n\n        var formData: CLDNMultipartFormData?\n        var request: URLRequest?\n        var streamingFromDisk: Bool?\n\n        // When\n        CLDNSessionManager.default.upload(\n            multipartFormData: { multipartFormData in\n                multipartFormData.append(uploadData, withName: \"upload_data\")\n                formData = multipartFormData\n            },\n            to: urlString,\n            encodingCompletion: { result in\n                switch result {\n                case let .success(upload, uploadStreamingFromDisk, _):\n                    streamingFromDisk = uploadStreamingFromDisk\n\n                    upload.response { resp in\n                        request = resp.request\n                        expectation.fulfill()\n                    }\n                case .failure:\n                    expectation.fulfill()\n                }\n            }\n        )\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(streamingFromDisk, \"streaming from disk should not be nil\")\n\n        if let streamingFromDisk = streamingFromDisk {\n            XCTAssertFalse(streamingFromDisk, \"streaming from disk should be false\")\n        }\n\n        if\n            let request = request,\n            let multipartFormData = formData,\n            let contentType = request.value(forHTTPHeaderField: \"Content-Type\")\n        {\n            XCTAssertEqual(contentType, multipartFormData.contentType, \"Content-Type header value should match\")\n        } else {\n            XCTFail(\"Content-Type header value should not be nil\")\n        }\n    }\n\n    func testThatUploadingMultipartFormDataAboveMemoryThresholdStreamsFromDisk() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let frenchData = \"français\".data(using: .utf8, allowLossyConversion: false)!\n        let japaneseData = \"日本語\".data(using: .utf8, allowLossyConversion: false)!\n\n        let expectation = self.expectation(description: \"multipart form data upload should succeed\")\n\n        var streamingFromDisk: Bool?\n        var streamFileURL: URL?\n\n        // When\n        CLDNSessionManager.default.upload(\n            multipartFormData: { multipartFormData in\n                multipartFormData.append(frenchData, withName: \"french\")\n                multipartFormData.append(japaneseData, withName: \"japanese\")\n            },\n            usingThreshold: 0,\n            to: urlString,\n            encodingCompletion: { result in\n                switch result {\n                case let .success(upload, uploadStreamingFromDisk, uploadStreamFileURL):\n                    streamingFromDisk = uploadStreamingFromDisk\n                    streamFileURL = uploadStreamFileURL\n\n                    upload.response { _ in\n                        expectation.fulfill()\n                    }\n                case .failure:\n                    expectation.fulfill()\n                }\n            }\n        )\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(streamingFromDisk, \"streaming from disk should not be nil\")\n        XCTAssertNotNil(streamFileURL, \"stream file URL should not be nil\")\n\n        if let streamingFromDisk = streamingFromDisk, let streamFilePath = streamFileURL?.path {\n            XCTAssertTrue(streamingFromDisk, \"streaming from disk should be true\")\n            XCTAssertFalse(FileManager.default.fileExists(atPath: streamFilePath), \"stream file path should not exist\")\n        }\n    }\n\n    func testThatUploadingMultipartFormDataAboveMemoryThresholdSetsContentTypeHeader() {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let uploadData = \"upload data\".data(using: .utf8, allowLossyConversion: false)!\n\n        let expectation = self.expectation(description: \"multipart form data upload should succeed\")\n\n        var formData: CLDNMultipartFormData?\n        var request: URLRequest?\n        var streamingFromDisk: Bool?\n\n        // When\n        CLDNSessionManager.default.upload(\n            multipartFormData: { multipartFormData in\n                multipartFormData.append(uploadData, withName: \"upload_data\")\n                formData = multipartFormData\n            },\n            usingThreshold: 0,\n            to: urlString,\n            encodingCompletion: { result in\n                switch result {\n                case let .success(upload, uploadStreamingFromDisk, _):\n                    streamingFromDisk = uploadStreamingFromDisk\n\n                    upload.response { resp in\n                        request = resp.request\n                        expectation.fulfill()\n                    }\n                case .failure:\n                    expectation.fulfill()\n                }\n            }\n        )\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(streamingFromDisk, \"streaming from disk should not be nil\")\n\n        if let streamingFromDisk = streamingFromDisk {\n            XCTAssertTrue(streamingFromDisk, \"streaming from disk should be true\")\n        }\n\n        if\n            let request = request,\n            let multipartFormData = formData,\n            let contentType = request.value(forHTTPHeaderField: \"Content-Type\")\n        {\n            XCTAssertEqual(contentType, multipartFormData.contentType, \"Content-Type header value should match\")\n        } else {\n            XCTFail(\"Content-Type header value should not be nil\")\n        }\n    }\n\n#if os(macOS)\n    func testThatUploadingMultipartFormDataOnBackgroundSessionWritesDataToFileToAvoidCrash() {\n        // Given\n        let manager: SessionManager = {\n            let identifier = \"org.cloudinary.uploadtests.\\(UUID().uuidString)\"\n            let configuration = URLSessionConfiguration.background(withIdentifier: identifier)\n\n            return SessionManager(configuration: configuration, serverTrustPolicyManager: nil)\n        }()\n\n        let urlString = \"https://httpbin.org/post\"\n        let french = \"français\".data(using: .utf8, allowLossyConversion: false)!\n        let japanese = \"日本語\".data(using: .utf8, allowLossyConversion: false)!\n\n        let expectation = self.expectation(description: \"multipart form data upload should succeed\")\n\n        var request: URLRequest?\n        var response: HTTPURLResponse?\n        var data: Data?\n        var error: Error?\n        var streamingFromDisk: Bool?\n\n        // When\n        manager.upload(\n            multipartFormData: { multipartFormData in\n                multipartFormData.append(french, withName: \"french\")\n                multipartFormData.append(japanese, withName: \"japanese\")\n            },\n            to: urlString,\n            encodingCompletion: { result in\n                switch result {\n                case let .success(upload, uploadStreamingFromDisk, _):\n                    streamingFromDisk = uploadStreamingFromDisk\n\n                    upload.response { defaultResponse in\n                        request = defaultResponse.request\n                        response = defaultResponse.response\n                        data = defaultResponse.data\n                        error = defaultResponse.error\n\n                        expectation.fulfill()\n                    }\n                case .failure:\n                    expectation.fulfill()\n                }\n            }\n        )\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(request, \"request should not be nil\")\n        XCTAssertNotNil(response, \"response should not be nil\")\n        XCTAssertNotNil(data, \"data should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n\n        if let streamingFromDisk = streamingFromDisk {\n            XCTAssertTrue(streamingFromDisk, \"streaming from disk should be true\")\n        } else {\n            XCTFail(\"streaming from disk should not be nil\")\n        }\n    }\n#endif\n\n    // MARK: Combined Test Execution\n\n    private func executeMultipartFormDataUploadRequestWithProgress(streamFromDisk: Bool) {\n        // Given\n        let urlString = \"https://httpbin.org/post\"\n        let loremData1: Data = {\n            var loremValues: [String] = []\n            for _ in 1...1_500 {\n                loremValues.append(\"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\")\n            }\n\n            return loremValues.joined(separator: \" \").data(using: .utf8, allowLossyConversion: false)!\n        }()\n        let loremData2: Data = {\n            var loremValues: [String] = []\n            for _ in 1...1_500 {\n                loremValues.append(\"Lorem ipsum dolor sit amet, nam no graeco recusabo appellantur.\")\n            }\n\n            return loremValues.joined(separator: \" \").data(using: .utf8, allowLossyConversion: false)!\n        }()\n\n        let expectation = self.expectation(description: \"multipart form data upload should succeed\")\n\n        var uploadProgressValues: [Double] = []\n        var downloadProgressValues: [Double] = []\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        CLDNSessionManager.default.upload(\n            multipartFormData: { multipartFormData in\n                multipartFormData.append(loremData1, withName: \"lorem1\")\n                multipartFormData.append(loremData2, withName: \"lorem2\")\n            },\n            usingThreshold: streamFromDisk ? 0 : 100_000_000,\n            to: urlString,\n            encodingCompletion: { result in\n                switch result {\n                case .success(let upload, _, _):\n                    upload\n                        .uploadProgress { progress in\n                            uploadProgressValues.append(progress.fractionCompleted)\n                        }\n                        .downloadProgress { progress in\n                            downloadProgressValues.append(progress.fractionCompleted)\n                        }\n                        .response { resp in\n                            response = resp\n                            expectation.fulfill()\n                        }\n                case .failure:\n                    expectation.fulfill()\n                }\n            }\n        )\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        var previousUploadProgress: Double = uploadProgressValues.first ?? 0.0\n\n        for progress in uploadProgressValues {\n            XCTAssertGreaterThanOrEqual(progress, previousUploadProgress)\n            previousUploadProgress = progress\n        }\n\n        if let lastProgressValue = uploadProgressValues.last {\n            XCTAssertEqual(lastProgressValue, 1.0)\n        } else {\n            XCTFail(\"last item in uploadProgressValues should not be nil\")\n        }\n\n        var previousDownloadProgress: Double = downloadProgressValues.first ?? 0.0\n\n        for progress in downloadProgressValues {\n            XCTAssertGreaterThanOrEqual(progress, previousDownloadProgress)\n            previousDownloadProgress = progress\n        }\n\n        if let lastProgressValue = downloadProgressValues.last {\n            XCTAssertEqual(lastProgressValue, 1.0)\n        } else {\n            XCTFail(\"last item in downloadProgressValues should not be nil\")\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Extensions/CLDNDataResponse+CloudinaryTests.swift",
    "content": "// \n//  CLDNDataResponse+CloudinaryTests.swift\n//  Cloudinary_Tests\n//\n//  Created on 30/03/2020.\n//  Copyright (c) 2020 Cloudinary. All rights reserved.\n//\n\n@testable import Cloudinary\nimport Foundation\n\n// MARK: - MAP Method\n\nextension CLDNDataResponse {\n    /// Evaluates the specified closure when the result of this `CLDNDataResponse` is a success, passing the unwrapped\n    /// result value as a parameter.\n    ///\n    /// Use the `map` method with a closure that does not throw. For example:\n    ///\n    ///     let possibleData: CLDNDataResponse<Data> = ...\n    ///     let possibleInt = possibleData.map { $0.count }\n    ///\n    /// - parameter transform: A closure that takes the success value of the instance's result.\n    ///\n    /// - returns: A `CLDNDataResponse` whose result wraps the value returned by the given closure. If this instance's\n    ///            result is a failure, returns a response wrapping the same failure.\n    internal func map<T>(_ transform: (Value) -> T) -> CLDNDataResponse<T> {\n        var response = CLDNDataResponse<T>(\n            request: request,\n            response: self.response,\n            data: data,\n            result: result.map(transform),\n            timeline: timeline\n        )\n\n        response._metrics = _metrics\n\n        return response\n    }\n\n    /// Evaluates the given closure when the result of this `CLDNDataResponse` is a success, passing the unwrapped result\n    /// value as a parameter.\n    ///\n    /// Use the `flatMap` method with a closure that may throw an error. For example:\n    ///\n    ///     let possibleData: CLDNDataResponse<Data> = ...\n    ///     let possibleObject = possibleData.flatMap {\n    ///         try JSONSerialization.jsonObject(with: $0)\n    ///     }\n    ///\n    /// - parameter transform: A closure that takes the success value of the instance's result.\n    ///\n    /// - returns: A success or failure `CLDNDataResponse` depending on the result of the given closure. If this instance's\n    ///            result is a failure, returns the same failure.\n    internal func flatMap<T>(_ transform: (Value) throws -> T) -> CLDNDataResponse<T> {\n        var response = CLDNDataResponse<T>(\n            request: request,\n            response: self.response,\n            data: data,\n            result: result.flatMap(transform),\n            timeline: timeline\n        )\n\n        response._metrics = _metrics\n\n        return response\n    }\n\n    /// Evaluates the specified closure when the `CLDNDataResponse` is a failure, passing the unwrapped error as a parameter.\n    ///\n    /// Use the `mapError` function with a closure that does not throw. For example:\n    ///\n    ///     let possibleData: CLDNDataResponse<Data> = ...\n    ///     let withMyError = possibleData.mapError { MyError.error($0) }\n    ///\n    /// - Parameter transform: A closure that takes the error of the instance.\n    /// - Returns: A `CLDNDataResponse` instance containing the result of the transform.\n    internal func mapError<E: Error>(_ transform: (Error) -> E) -> CLDNDataResponse {\n        var response = CLDNDataResponse(\n            request: request,\n            response: self.response,\n            data: data,\n            result: result.mapError(transform),\n            timeline: timeline\n        )\n\n        response._metrics = _metrics\n\n        return response\n    }\n\n    /// Evaluates the specified closure when the `CLDNDataResponse` is a failure, passing the unwrapped error as a parameter.\n    ///\n    /// Use the `flatMapError` function with a closure that may throw an error. For example:\n    ///\n    ///     let possibleData: CLDNDataResponse<Data> = ...\n    ///     let possibleObject = possibleData.flatMapError {\n    ///         try someFailableFunction(taking: $0)\n    ///     }\n    ///\n    /// - Parameter transform: A throwing closure that takes the error of the instance.\n    ///\n    /// - Returns: A `CLDNDataResponse` instance containing the result of the transform.\n    internal func flatMapError<E: Error>(_ transform: (Error) throws -> E) -> CLDNDataResponse {\n        var response = CLDNDataResponse(\n            request: request,\n            response: self.response,\n            data: data,\n            result: result.flatMapError(transform),\n            timeline: timeline\n        )\n\n        response._metrics = _metrics\n\n        return response\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Extensions/CLDNError+CloudinaryTests.swift",
    "content": "//\n//  CLDNError+CloudinaryTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\n\nextension CLDNError {\n\n    // ParameterEncodingFailureReason\n\n    var isMissingURLFailed: Bool {\n        if case let .parameterEncodingFailed(reason) = self, reason.isMissingURL { return true }\n        return false\n    }\n\n    var isJSONEncodingFailed: Bool {\n        if case let .parameterEncodingFailed(reason) = self, reason.isJSONEncodingFailed { return true }\n        return false\n    }\n\n    var isPropertyListEncodingFailed: Bool {\n        if case let .parameterEncodingFailed(reason) = self, reason.isPropertyListEncodingFailed { return true }\n        return false\n    }\n\n    // MultipartEncodingFailureReason\n\n    var isBodyPartURLInvalid: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isBodyPartURLInvalid { return true }\n        return false\n    }\n\n    var isBodyPartFilenameInvalid: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isBodyPartFilenameInvalid { return true }\n        return false\n    }\n\n    var isBodyPartFileNotReachable: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isBodyPartFileNotReachable { return true }\n        return false\n    }\n\n    var isBodyPartFileNotReachableWithError: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isBodyPartFileNotReachableWithError { return true }\n        return false\n    }\n\n    var isBodyPartFileIsDirectory: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isBodyPartFileIsDirectory { return true }\n        return false\n    }\n\n    var isBodyPartFileSizeNotAvailable: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isBodyPartFileSizeNotAvailable { return true }\n        return false\n    }\n\n    var isBodyPartFileSizeQueryFailedWithError: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isBodyPartFileSizeQueryFailedWithError { return true }\n        return false\n    }\n\n    var isBodyPartInputStreamCreationFailed: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isBodyPartInputStreamCreationFailed { return true }\n        return false\n    }\n\n    var isOutputStreamCreationFailed: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isOutputStreamCreationFailed { return true }\n        return false\n    }\n\n    var isOutputStreamFileAlreadyExists: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isOutputStreamFileAlreadyExists { return true }\n        return false\n    }\n\n    var isOutputStreamURLInvalid: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isOutputStreamURLInvalid { return true }\n        return false\n    }\n\n    var isOutputStreamWriteFailed: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isOutputStreamWriteFailed { return true }\n        return false\n    }\n\n    var isInputStreamReadFailed: Bool {\n        if case let .multipartEncodingFailed(reason) = self, reason.isInputStreamReadFailed { return true }\n        return false\n    }\n\n    // ResponseSerializationFailureReason\n\n    var isInputDataNil: Bool {\n        if case let .responseSerializationFailed(reason) = self, reason.isInputDataNil { return true }\n        return false\n    }\n\n    var isInputDataNilOrZeroLength: Bool {\n        if case let .responseSerializationFailed(reason) = self, reason.isInputDataNilOrZeroLength { return true }\n        return false\n    }\n\n    var isInputFileNil: Bool {\n        if case let .responseSerializationFailed(reason) = self, reason.isInputFileNil { return true }\n        return false\n    }\n\n    var isInputFileReadFailed: Bool {\n        if case let .responseSerializationFailed(reason) = self, reason.isInputFileReadFailed { return true }\n        return false\n    }\n\n    var isStringSerializationFailed: Bool {\n        if case let .responseSerializationFailed(reason) = self, reason.isStringSerializationFailed { return true }\n        return false\n    }\n\n    var isJSONSerializationFailed: Bool {\n        if case let .responseSerializationFailed(reason) = self, reason.isJSONSerializationFailed { return true }\n        return false\n    }\n\n    var isPropertyListSerializationFailed: Bool {\n        if case let .responseSerializationFailed(reason) = self, reason.isPropertyListSerializationFailed { return true }\n        return false\n    }\n\n    // ResponseValidationFailureReason\n\n    var isDataFileNil: Bool {\n        if case let .responseValidationFailed(reason) = self, reason.isDataFileNil { return true }\n        return false\n    }\n\n    var isDataFileReadFailed: Bool {\n        if case let .responseValidationFailed(reason) = self, reason.isDataFileReadFailed { return true }\n        return false\n    }\n\n    var isMissingContentType: Bool {\n        if case let .responseValidationFailed(reason) = self, reason.isMissingContentType { return true }\n        return false\n    }\n\n    var isUnacceptableContentType: Bool {\n        if case let .responseValidationFailed(reason) = self, reason.isUnacceptableContentType { return true }\n        return false\n    }\n\n    var isUnacceptableStatusCode: Bool {\n        if case let .responseValidationFailed(reason) = self, reason.isUnacceptableStatusCode { return true }\n        return false\n    }\n}\n\n// MARK: -\n\nextension CLDNError.ParameterEncodingFailureReason {\n    var isMissingURL: Bool {\n        if case .missingURL = self { return true }\n        return false\n    }\n\n    var isJSONEncodingFailed: Bool {\n        if case .jsonEncodingFailed = self { return true }\n        return false\n    }\n\n    var isPropertyListEncodingFailed: Bool {\n        if case .propertyListEncodingFailed = self { return true }\n        return false\n    }\n}\n\n// MARK: -\n\nextension CLDNError.MultipartEncodingFailureReason {\n    var isBodyPartURLInvalid: Bool {\n        if case .bodyPartURLInvalid = self { return true }\n        return false\n    }\n\n    var isBodyPartFilenameInvalid: Bool {\n        if case .bodyPartFilenameInvalid = self { return true }\n        return false\n    }\n\n    var isBodyPartFileNotReachable: Bool {\n        if case .bodyPartFileNotReachable = self { return true }\n        return false\n    }\n\n    var isBodyPartFileNotReachableWithError: Bool {\n        if case .bodyPartFileNotReachableWithError = self { return true }\n        return false\n    }\n\n    var isBodyPartFileIsDirectory: Bool {\n        if case .bodyPartFileIsDirectory = self { return true }\n        return false\n    }\n\n    var isBodyPartFileSizeNotAvailable: Bool {\n        if case .bodyPartFileSizeNotAvailable = self { return true }\n        return false\n    }\n\n    var isBodyPartFileSizeQueryFailedWithError: Bool {\n        if case .bodyPartFileSizeQueryFailedWithError = self { return true }\n        return false\n    }\n\n    var isBodyPartInputStreamCreationFailed: Bool {\n        if case .bodyPartInputStreamCreationFailed = self { return true }\n        return false\n    }\n\n    var isOutputStreamCreationFailed: Bool {\n        if case .outputStreamCreationFailed = self { return true }\n        return false\n    }\n\n    var isOutputStreamFileAlreadyExists: Bool {\n        if case .outputStreamFileAlreadyExists = self { return true }\n        return false\n    }\n\n    var isOutputStreamURLInvalid: Bool {\n        if case .outputStreamURLInvalid = self { return true }\n        return false\n    }\n\n    var isOutputStreamWriteFailed: Bool {\n        if case .outputStreamWriteFailed = self { return true }\n        return false\n    }\n\n    var isInputStreamReadFailed: Bool {\n        if case .inputStreamReadFailed = self { return true }\n        return false\n    }\n}\n\n// MARK: -\n\nextension CLDNError.ResponseSerializationFailureReason {\n    var isInputDataNil: Bool {\n        if case .inputDataNil = self { return true }\n        return false\n    }\n\n    var isInputDataNilOrZeroLength: Bool {\n        if case .inputDataNilOrZeroLength = self { return true }\n        return false\n    }\n\n    var isInputFileNil: Bool {\n        if case .inputFileNil = self { return true }\n        return false\n    }\n\n    var isInputFileReadFailed: Bool {\n        if case .inputFileReadFailed = self { return true }\n        return false\n    }\n\n    var isStringSerializationFailed: Bool {\n        if case .stringSerializationFailed = self { return true }\n        return false\n    }\n\n    var isJSONSerializationFailed: Bool {\n        if case .jsonSerializationFailed = self { return true }\n        return false\n    }\n\n    var isPropertyListSerializationFailed: Bool {\n        if case .propertyListSerializationFailed = self { return true }\n        return false\n    }\n}\n\n// MARK: -\n\nextension CLDNError.ResponseValidationFailureReason {\n    var isDataFileNil: Bool {\n        if case .dataFileNil = self { return true }\n        return false\n    }\n\n    var isDataFileReadFailed: Bool {\n        if case .dataFileReadFailed = self { return true }\n        return false\n    }\n\n    var isMissingContentType: Bool {\n        if case .missingContentType = self { return true }\n        return false\n    }\n\n    var isUnacceptableContentType: Bool {\n        if case .unacceptableContentType = self { return true }\n        return false\n    }\n\n    var isUnacceptableStatusCode: Bool {\n        if case .unacceptableStatusCode = self { return true }\n        return false\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Extensions/CLDNResult+CloudinaryTests.swift",
    "content": "//\n//  CLDNResult+CloudinaryTests.swift\n//  Cloudinary_Tests\n//\n//  Created on 30/03/2020.\n//  Copyright (c) 2020 Cloudinary. All rights reserved.\n//\n\n@testable import Cloudinary\nimport Foundation\n\n// MARK: - MAP Method\n\nextension CLDNResult\n{\n    /// Evaluates the specified closure when the `CLDNResult` is a success, passing the unwrapped value as a parameter.\n    ///\n    /// Use the `map` method with a closure that does not throw. For example:\n    ///\n    ///     let possibleData: CLDNResult<Data> = .success(Data())\n    ///     let possibleInt = possibleData.map { $0.count }\n    ///     try print(possibleInt.unwrap())\n    ///     // Prints \"0\"\n    ///\n    ///     let noData: CLDNResult<Data> = .failure(error)\n    ///     let noInt = noData.map { $0.count }\n    ///     try print(noInt.unwrap())\n    ///     // Throws error\n    ///\n    /// - parameter transform: A closure that takes the success value of the `CLDNResult` instance.\n    ///\n    /// - returns: A `CLDNResult` containing the result of the given closure. If this instance is a failure, returns the\n    ///            same failure.\n    internal func map<T>(_ transform: (Value) -> T) -> CLDNResult<T> {\n        switch self {\n        case .success(let value):\n            return .success(transform(value))\n        case .failure(let error):\n            return .failure(error)\n        }\n    }\n    \n    /// Evaluates the specified closure when the `CLDNResult` is a success, passing the unwrapped value as a parameter.\n    ///\n    /// Use the `flatMap` method with a closure that may throw an error. For example:\n    ///\n    ///     let possibleData: CLDNResult<Data> = .success(Data(...))\n    ///     let possibleObject = possibleData.flatMap {\n    ///         try JSONSerialization.jsonObject(with: $0)\n    ///     }\n    ///\n    /// - parameter transform: A closure that takes the success value of the instance.\n    ///\n    /// - returns: A `CLDNResult` containing the result of the given closure. If this instance is a failure, returns the\n    ///            same failure.\n    internal func flatMap<T>(_ transform: (Value) throws -> T) -> CLDNResult<T> {\n        switch self {\n        case .success(let value):\n            do {\n                return try .success(transform(value))\n            } catch {\n                return .failure(error)\n            }\n        case .failure(let error):\n            return .failure(error)\n        }\n    }\n    \n    /// Evaluates the specified closure when the `CLDNResult` is a failure, passing the unwrapped error as a parameter.\n    ///\n    /// Use the `mapError` function with a closure that does not throw. For example:\n    ///\n    ///     let possibleData: CLDNResult<Data> = .failure(someError)\n    ///     let withMyError: CLDNResult<Data> = possibleData.mapError { MyError.error($0) }\n    ///\n    /// - Parameter transform: A closure that takes the error of the instance.\n    /// - Returns: A `CLDNResult` instance containing the result of the transform. If this instance is a success, returns\n    ///            the same instance.\n    internal func mapError<T: Error>(_ transform: (Error) -> T) -> CLDNResult {\n        switch self {\n        case .failure(let error):\n            return .failure(transform(error))\n        case .success:\n            return self\n        }\n    }\n    \n    /// Evaluates the specified closure when the `CLDNResult` is a failure, passing the unwrapped error as a parameter.\n    ///\n    /// Use the `flatMapError` function with a closure that may throw an error. For example:\n    ///\n    ///     let possibleData: CLDNResult<Data> = .success(Data(...))\n    ///     let possibleObject = possibleData.flatMapError {\n    ///         try someFailableFunction(taking: $0)\n    ///     }\n    ///\n    /// - Parameter transform: A throwing closure that takes the error of the instance.\n    ///\n    /// - Returns: A `CLDNResult` instance containing the result of the transform. If this instance is a success, returns\n    ///            the same instance.\n    internal func flatMapError<T: Error>(_ transform: (Error) throws -> T) -> CLDNResult {\n        switch self {\n        case .failure(let error):\n            do {\n                return try .failure(transform(error))\n            } catch {\n                return .failure(error)\n            }\n        case .success:\n            return self\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Extensions/FileManager+CloudinaryTests.swift",
    "content": "//\n//  FileManager+CloudinaryTests.swift\n//\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\nimport Foundation\n\nextension FileManager {\n\n    // MARK: - Common Directories\n\n    static var temporaryDirectoryPath: String {\n        return NSTemporaryDirectory()\n    }\n\n    static var temporaryDirectoryURL: URL {\n        return URL(fileURLWithPath: FileManager.temporaryDirectoryPath, isDirectory: true)\n    }\n\n    // MARK: - File System Modification\n\n    @discardableResult\n    static func createDirectory(atPath path: String) -> Bool {\n        do {\n            try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)\n            return true\n        } catch {\n            return false\n        }\n    }\n\n    @discardableResult\n    static func createDirectory(at url: URL) -> Bool {\n        return createDirectory(atPath: url.path)\n    }\n\n    @discardableResult\n    static func removeItem(atPath path: String) -> Bool {\n        do {\n            try FileManager.default.removeItem(atPath: path)\n            return true\n        } catch {\n            return false\n        }\n    }\n\n    @discardableResult\n    static func removeItem(at url: URL) -> Bool {\n        return removeItem(atPath: url.path)\n    }\n\n    @discardableResult\n    static func removeAllItemsInsideDirectory(atPath path: String) -> Bool {\n        let enumerator = FileManager.default.enumerator(atPath: path)\n        var result = true\n\n        while let fileName = enumerator?.nextObject() as? String {\n            let success = removeItem(atPath: path + \"/\\(fileName)\")\n            if !success { result = false }\n        }\n\n        return result\n    }\n\n    @discardableResult\n    static func removeAllItemsInsideDirectory(at url: URL) -> Bool {\n        return removeAllItemsInsideDirectory(atPath: url.path)\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Features/CacheTests.swift",
    "content": "//\n//  CacheTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\n/// This test case tests all implemented cache policies against various `Cache-Control` header values. These tests\n/// are meant to cover the main cases of `Cache-Control` header usage, but are by no means exhaustive.\n///\n/// These tests work as follows:\n///\n/// - Set up an `URLCache`\n/// - Set up an `Cloudinary.CLDNSessionManager`\n/// - Execute requests for all `Cache-Control` header values to prime the `NSURLCache` with cached responses\n/// - Start up a new test\n/// - Execute another round of the same requests with a given `URLRequestCachePolicy`\n/// - Verify whether the response came from the cache or from the network\n///     - This is determined by whether the cached response timestamp matches the new response timestamp\n///\n/// An important thing to note is the difference in behavior between iOS and macOS. On iOS, a response with\n/// a `Cache-Control` header value of `no-store` is still written into the `NSURLCache` where on macOS, it is not.\n/// The different tests below reflect and demonstrate this behavior.\n///\n/// For information about `Cache-Control` HTTP headers, please refer to RFC 2616 - Section 14.9.\nclass CacheTestCase: BaseTestCase {\n\n    // MARK: -\n\n    struct CacheControl {\n        static let publicControl = \"public\"\n        static let privateControl = \"private\"\n        static let maxAgeNonExpired = \"max-age=3600\"\n        static let maxAgeExpired = \"max-age=0\"\n        static let noCache = \"no-cache\"\n        static let noStore = \"no-store\"\n\n        static var allValues: [String] {\n            return [\n                CacheControl.publicControl,\n                CacheControl.privateControl,\n                CacheControl.maxAgeNonExpired,\n                CacheControl.maxAgeExpired,\n                CacheControl.noCache,\n                CacheControl.noStore\n            ]\n        }\n    }\n\n    // MARK: - Properties\n\n    var urlCache: URLCache!\n    var manager: CLDNSessionManager!\n\n    let urlString = \"https://httpbin.org/response-headers\"\n    let requestTimeout: TimeInterval = 30\n\n    var requests: [String: URLRequest] = [:]\n    var timestamps: [String: String] = [:]\n\n    // MARK: - setup and teardown\n\n    override func setUp() {\n        super.setUp()\n\n        urlCache = {\n            let capacity = 50 * 1024 * 1024 // MBs\n            let urlCache = URLCache(memoryCapacity: capacity, diskCapacity: capacity, diskPath: nil)\n\n            return urlCache\n        }()\n\n        manager = {\n            let configuration: URLSessionConfiguration = {\n                let configuration = URLSessionConfiguration.default\n                configuration.httpAdditionalHeaders = CLDNSessionManager.defaultHTTPHeaders\n                configuration.requestCachePolicy = .useProtocolCachePolicy\n                configuration.urlCache = urlCache\n\n                return configuration\n            }()\n\n            let manager = CLDNSessionManager(configuration: configuration)\n\n            return manager\n        }()\n\n//        primeCachedResponses()\n    }\n\n    override func tearDown() {\n        super.tearDown()\n\n        requests.removeAll()\n        timestamps.removeAll()\n\n        urlCache.removeAllCachedResponses()\n    }\n\n    // MARK: - Cache Priming Methods\n\n    /**\n        Executes a request for all `Cache-Control` header values to load the response into the `URLCache`.\n\n        This implementation leverages dispatch groups to execute all the requests as well as wait an additional\n        second before returning. This ensures the cache contains responses for all requests that are at least\n        one second old. This allows the tests to distinguish whether the subsequent responses come from the cache\n        or the network based on the timestamp of the response.\n    */\n    func primeCachedResponses() {\n        let dispatchGroup = DispatchGroup()\n        let serialQueue = DispatchQueue(label: \"com.cloudinary.cache-tests\")\n\n        for cacheControl in CacheControl.allValues {\n            dispatchGroup.enter()\n\n            let request = startRequest(\n                cacheControl: cacheControl,\n                queue: serialQueue,\n                completion: { _, response in\n                    let timestamp = response!.allHeaderFields[\"Date\"] as! String\n                    self.timestamps[cacheControl] = timestamp\n\n                    dispatchGroup.leave()\n                }\n            )\n\n            requests[cacheControl] = request\n        }\n\n        // Wait for all requests to complete\n        _ = dispatchGroup.wait(timeout: DispatchTime.now() + Double(Int64(30.0 * Float(NSEC_PER_SEC))) / Double(NSEC_PER_SEC))\n\n        // Pause for 2 additional seconds to ensure all timestamps will be different\n        dispatchGroup.enter()\n        serialQueue.asyncAfter(deadline: DispatchTime.now() + Double(Int64(2.0 * Float(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)) {\n            dispatchGroup.leave()\n        }\n\n        // Wait for our 2 second pause to complete\n        _ = dispatchGroup.wait(timeout: DispatchTime.now() + Double(Int64(10.0 * Float(NSEC_PER_SEC))) / Double(NSEC_PER_SEC))\n    }\n\n    // MARK: - Request Helper Methods\n\n    func urlRequest(cacheControl: String, cachePolicy: NSURLRequest.CachePolicy) -> URLRequest {\n        let parameters = [\"Cache-Control\": cacheControl]\n        let url = URL(string: urlString)!\n\n        var urlRequest = URLRequest(url: url, cachePolicy: cachePolicy, timeoutInterval: requestTimeout)\n        urlRequest.httpMethod = CLDNHTTPMethod.get.rawValue\n\n        do {\n            return try CLDNURLEncoding.default.CLDN_Encode(urlRequest, with: parameters)\n        } catch {\n            return urlRequest\n        }\n    }\n\n    @discardableResult\n    func startRequest(\n        cacheControl: String,\n        cachePolicy: NSURLRequest.CachePolicy = .useProtocolCachePolicy,\n        queue: DispatchQueue = DispatchQueue.main,\n        completion: @escaping (URLRequest?, HTTPURLResponse?) -> Void)\n        -> URLRequest\n    {\n        let urlRequest = self.urlRequest(cacheControl: cacheControl, cachePolicy: cachePolicy)\n        let request = manager.request(urlRequest)\n\n        request.response(\n            queue: queue,\n            completionHandler: { response in\n                completion(response.request, response.response)\n            }\n        )\n\n        return urlRequest\n    }\n\n    // MARK: - Test Execution and Verification\n\n    func executeTest(\n        cachePolicy: NSURLRequest.CachePolicy,\n        cacheControl: String,\n        shouldReturnCachedResponse: Bool)\n    {\n        // Given\n        let expectation = self.expectation(description: \"GET request to httpbin\")\n        var response: HTTPURLResponse?\n\n        // When\n        startRequest(cacheControl: cacheControl, cachePolicy: cachePolicy) { _, responseResponse in\n            response = responseResponse\n            expectation.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        verifyResponse(response, forCacheControl: cacheControl, isCachedResponse: shouldReturnCachedResponse)\n    }\n\n    func verifyResponse(_ response: HTTPURLResponse?, forCacheControl cacheControl: String, isCachedResponse: Bool) {\n        guard let cachedResponseTimestamp = timestamps[cacheControl] else {\n            XCTFail(\"cached response timestamp should not be nil\")\n            return\n        }\n\n        if let response = response, let timestamp = response.allHeaderFields[\"Date\"] as? String {\n            if isCachedResponse {\n                XCTAssertEqual(timestamp, cachedResponseTimestamp, \"timestamps should be equal\")\n            } else {\n                XCTAssertNotEqual(timestamp, cachedResponseTimestamp, \"timestamps should not be equal\")\n            }\n        } else {\n            XCTFail(\"response should not be nil\")\n        }\n    }\n\n    // MARK: - Cache Helper Methods\n\n    private func isCachedResponseForNoStoreHeaderExpected() -> Bool {\n    #if os(iOS)\n        if #available(iOS 8.3, *) {\n            return false\n        } else {\n            return true\n        }\n    #else\n        return false\n    #endif\n    }\n\n    // MARK: - Tests\n\n//    func testURLCacheContainsCachedResponsesForAllRequests() {\n//        // Given\n//        let publicRequest = requests[CacheControl.publicControl]!\n//        let privateRequest = requests[CacheControl.privateControl]!\n//        let maxAgeNonExpiredRequest = requests[CacheControl.maxAgeNonExpired]!\n//        let maxAgeExpiredRequest = requests[CacheControl.maxAgeExpired]!\n//        let noCacheRequest = requests[CacheControl.noCache]!\n//        let noStoreRequest = requests[CacheControl.noStore]!\n//\n//        // When\n//        let publicResponse = urlCache.cachedResponse(for: publicRequest)\n//        let privateResponse = urlCache.cachedResponse(for: privateRequest)\n//        let maxAgeNonExpiredResponse = urlCache.cachedResponse(for: maxAgeNonExpiredRequest)\n//        let maxAgeExpiredResponse = urlCache.cachedResponse(for: maxAgeExpiredRequest)\n//        let noCacheResponse = urlCache.cachedResponse(for: noCacheRequest)\n//        let noStoreResponse = urlCache.cachedResponse(for: noStoreRequest)\n//\n//        // Then\n//        XCTAssertNotNil(publicResponse, \"\\(CacheControl.publicControl) response should not be nil\")\n//        XCTAssertNotNil(privateResponse, \"\\(CacheControl.privateControl) response should not be nil\")\n//        XCTAssertNotNil(maxAgeNonExpiredResponse, \"\\(CacheControl.maxAgeNonExpired) response should not be nil\")\n//        XCTAssertNotNil(maxAgeExpiredResponse, \"\\(CacheControl.maxAgeExpired) response should not be nil\")\n//        XCTAssertNotNil(noCacheResponse, \"\\(CacheControl.noCache) response should not be nil\")\n//\n//        if isCachedResponseForNoStoreHeaderExpected() {\n//            XCTAssertNotNil(noStoreResponse, \"\\(CacheControl.noStore) response should not be nil\")\n//        } else {\n//            XCTAssertNil(noStoreResponse, \"\\(CacheControl.noStore) response should be nil\")\n//        }\n//    }\n\n//    func skipped_testDefaultCachePolicy() {\n//        let cachePolicy: NSURLRequest.CachePolicy = .useProtocolCachePolicy\n//\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.publicControl, shouldReturnCachedResponse: false)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.privateControl, shouldReturnCachedResponse: false)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.maxAgeNonExpired, shouldReturnCachedResponse: true)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.maxAgeExpired, shouldReturnCachedResponse: false)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.noCache, shouldReturnCachedResponse: false)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.noStore, shouldReturnCachedResponse: false)\n//    }\n\n//    func testIgnoreLocalCacheDataPolicy() {\n//        let cachePolicy: NSURLRequest.CachePolicy = .reloadIgnoringLocalCacheData\n//\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.publicControl, shouldReturnCachedResponse: false)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.privateControl, shouldReturnCachedResponse: false)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.maxAgeNonExpired, shouldReturnCachedResponse: false)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.maxAgeExpired, shouldReturnCachedResponse: false)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.noCache, shouldReturnCachedResponse: false)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.noStore, shouldReturnCachedResponse: false)\n//    }\n\n//    func testUseLocalCacheDataIfExistsOtherwiseLoadFromNetworkPolicy() {\n//        let cachePolicy: NSURLRequest.CachePolicy = .returnCacheDataElseLoad\n//\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.publicControl, shouldReturnCachedResponse: true)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.privateControl, shouldReturnCachedResponse: true)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.maxAgeNonExpired, shouldReturnCachedResponse: true)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.maxAgeExpired, shouldReturnCachedResponse: true)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.noCache, shouldReturnCachedResponse: true)\n//\n//        if isCachedResponseForNoStoreHeaderExpected() {\n//            executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.noStore, shouldReturnCachedResponse: true)\n//        } else {\n//            executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.noStore, shouldReturnCachedResponse: false)\n//        }\n//    }\n\n//    func testUseLocalCacheDataAndDontLoadFromNetworkPolicy() {\n//        let cachePolicy: NSURLRequest.CachePolicy = .returnCacheDataDontLoad\n//\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.publicControl, shouldReturnCachedResponse: true)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.privateControl, shouldReturnCachedResponse: true)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.maxAgeNonExpired, shouldReturnCachedResponse: true)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.maxAgeExpired, shouldReturnCachedResponse: true)\n//        executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.noCache, shouldReturnCachedResponse: true)\n//\n//        if isCachedResponseForNoStoreHeaderExpected() {\n//            executeTest(cachePolicy: cachePolicy, cacheControl: CacheControl.noStore, shouldReturnCachedResponse: true)\n//        } else {\n//            // Given\n//            let expectation = self.expectation(description: \"GET request to httpbin\")\n//            var response: HTTPURLResponse?\n//\n//            // When\n//            startRequest(cacheControl: CacheControl.noStore, cachePolicy: cachePolicy) { _, responseResponse in\n//                response = responseResponse\n//                expectation.fulfill()\n//            }\n//\n//            waitForExpectations(timeout: timeout, handler: nil)\n//\n//            // Then\n//            XCTAssertNil(response, \"response should be nil\")\n//        }\n//    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Features/MultipartFormDataTests.swift",
    "content": "//\n//  MultipartFormDataTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nstruct EncodingCharacters {\n    static let crlf = \"\\r\\n\"\n}\n\nstruct BoundaryGenerator {\n    enum BoundaryType {\n        case initial, encapsulated, final\n    }\n\n    static func boundary(forBoundaryType boundaryType: BoundaryType, boundaryKey: String) -> String {\n        let boundary: String\n\n        switch boundaryType {\n        case .initial:\n            boundary = \"--\\(boundaryKey)\\(EncodingCharacters.crlf)\"\n        case .encapsulated:\n            boundary = \"\\(EncodingCharacters.crlf)--\\(boundaryKey)\\(EncodingCharacters.crlf)\"\n        case .final:\n            boundary = \"\\(EncodingCharacters.crlf)--\\(boundaryKey)--\\(EncodingCharacters.crlf)\"\n        }\n\n        return boundary\n    }\n\n    static func boundaryData(boundaryType: BoundaryType, boundaryKey: String) -> Data {\n        return BoundaryGenerator.boundary(\n            forBoundaryType: boundaryType,\n            boundaryKey: boundaryKey\n        ).data(using: .utf8, allowLossyConversion: false)!\n    }\n}\n\nprivate func temporaryFileURL() -> URL { return BaseTestCase.testDirectoryURL.appendingPathComponent(UUID().uuidString) }\n\n// MARK: -\n\nclass MultipartFormDataPropertiesTestCase: BaseTestCase {\n    func testThatContentTypeContainsBoundary() {\n        // Given\n        let multipartFormData = CLDNMultipartFormData()\n\n        // When\n        let boundary = multipartFormData.boundary\n\n        // Then\n        let expectedContentType = \"multipart/form-data; boundary=\\(boundary)\"\n        XCTAssertEqual(multipartFormData.contentType, expectedContentType, \"contentType should match expected value\")\n    }\n\n    func testThatContentLengthMatchesTotalBodyPartSize() {\n        // Given\n        let multipartFormData = CLDNMultipartFormData()\n        let data1 = \"Lorem ipsum dolor sit amet.\".data(using: .utf8, allowLossyConversion: false)!\n        let data2 = \"Vim at integre alterum.\".data(using: .utf8, allowLossyConversion: false)!\n\n        // When\n        multipartFormData.append(data1, withName: \"data1\")\n        multipartFormData.append(data2, withName: \"data2\")\n\n        // Then\n        let expectedContentLength = UInt64(data1.count + data2.count)\n        XCTAssertEqual(multipartFormData.contentLength, expectedContentLength, \"content length should match expected value\")\n    }\n}\n\n// MARK: -\n\nclass MultipartFormDataEncodingTestCase: BaseTestCase {\n    let crlf = EncodingCharacters.crlf\n\n    func testEncodingDataBodyPart() {\n        // Given\n        let multipartFormData = CLDNMultipartFormData()\n\n        let data = \"Lorem ipsum dolor sit amet.\".data(using: .utf8, allowLossyConversion: false)!\n        multipartFormData.append(data, withName: \"data\")\n\n        var encodedData: Data?\n\n        // When\n        do {\n            encodedData = try multipartFormData.encode()\n        } catch {\n            // No-op\n        }\n\n        // Then\n        XCTAssertNotNil(encodedData, \"encoded data should not be nil\")\n\n        if let encodedData = encodedData {\n            let boundary = multipartFormData.boundary\n\n            let expectedData = (\n                BoundaryGenerator.boundary(forBoundaryType: .initial, boundaryKey: boundary) +\n                \"Content-Disposition: form-data; name=\\\"data\\\"\\(crlf)\\(crlf)\" +\n                \"Lorem ipsum dolor sit amet.\" +\n                BoundaryGenerator.boundary(forBoundaryType: .final, boundaryKey: boundary)\n            ).data(using: .utf8, allowLossyConversion: false)!\n\n            XCTAssertEqual(encodedData, expectedData, \"encoded data should match expected data\")\n        }\n    }\n\n    func testEncodingMultipleDataBodyParts() {\n        // Given\n        let multipartFormData = CLDNMultipartFormData()\n\n        let frenchData = Data(\"français\".utf8)\n        let japaneseData = Data(\"日本語\".utf8)\n        let emojiData = Data(\"😃👍🏻🍻🎉\".utf8)\n\n        multipartFormData.append(frenchData, withName: \"french\")\n        multipartFormData.append(japaneseData, withName: \"japanese\", mimeType: \"text/plain\")\n        multipartFormData.append(emojiData, withName: \"emoji\", mimeType: \"text/plain\")\n\n        var encodedData: Data?\n\n        // When\n        do {\n            encodedData = try multipartFormData.encode()\n        } catch {\n            // No-op\n        }\n\n        // Then\n        XCTAssertNotNil(encodedData, \"encoded data should not be nil\")\n\n        if let encodedData = encodedData {\n            let boundary = multipartFormData.boundary\n\n            let expectedString = (\n                BoundaryGenerator.boundary(forBoundaryType: .initial, boundaryKey: boundary) +\n                    \"Content-Disposition: form-data; name=\\\"french\\\"\\(crlf)\\(crlf)\" +\n                    \"français\" +\n                    BoundaryGenerator.boundary(forBoundaryType: .encapsulated, boundaryKey: boundary) +\n                    \"Content-Type: text/plain\\(crlf)\" +\n                    \"Content-Disposition: form-data; name=\\\"japanese\\\"\\(crlf)\\(crlf)\" +\n                    \"日本語\" +\n                    BoundaryGenerator.boundary(forBoundaryType: .encapsulated, boundaryKey: boundary) +\n                    \"Content-Type: text/plain\\(crlf)\" +\n                    \"Content-Disposition: form-data; name=\\\"emoji\\\"\\(crlf)\\(crlf)\" +\n                    \"😃👍🏻🍻🎉\" +\n                    BoundaryGenerator.boundary(forBoundaryType: .final, boundaryKey: boundary)\n            )\n            let expectedData = Data(expectedString.utf8)\n\n            // XCTAssertEqual(encodedData, expectedData, \"encoded data should match expected data\")\n            XCTAssertEqual(encodedData.count, expectedData.count)\n        }\n    }\n\n    func testEncodingFileBodyPart() {\n        // Given\n        let multipartFormData = CLDNMultipartFormData()\n\n        let unicornImageURL = url(forResource: \"unicorn\", withExtension: \"png\")\n        multipartFormData.append(unicornImageURL, withName: \"unicorn\")\n\n        var encodedData: Data?\n\n        // When\n        do {\n            encodedData = try multipartFormData.encode()\n        } catch {\n            // No-op\n        }\n\n        // Then\n        XCTAssertNotNil(encodedData, \"encoded data should not be nil\")\n\n        if let encodedData = encodedData {\n            let boundary = multipartFormData.boundary\n\n            var expectedData = Data()\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .initial, boundaryKey: boundary))\n            expectedData.append(Data((\n                \"Content-Type: image/png\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"unicorn\\\"; filename=\\\"unicorn.png\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedData.append(try! Data(contentsOf: unicornImageURL))\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .final, boundaryKey: boundary))\n\n            // XCTAssertEqual(encodedData, expectedData, \"data should match expected data\")\n            XCTAssertEqual(encodedData.count, expectedData.count)\n        }\n    }\n\n    func testEncodingMultipleFileBodyParts() {\n        // Given\n        let multipartFormData = CLDNMultipartFormData()\n\n        let unicornImageURL = url(forResource: \"unicorn\", withExtension: \"png\")\n        let rainbowImageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n\n        multipartFormData.append(unicornImageURL, withName: \"unicorn\")\n        multipartFormData.append(rainbowImageURL, withName: \"rainbow\")\n\n        var encodedData: Data?\n\n        // When\n        do {\n            encodedData = try multipartFormData.encode()\n        } catch {\n            // No-op\n        }\n\n        // Then\n        XCTAssertNotNil(encodedData, \"encoded data should not be nil\")\n\n        if let encodedData = encodedData {\n            let boundary = multipartFormData.boundary\n\n            var expectedData = Data()\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .initial, boundaryKey: boundary))\n            expectedData.append(Data((\n                \"Content-Type: image/png\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"unicorn\\\"; filename=\\\"unicorn.png\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedData.append(try! Data(contentsOf: unicornImageURL))\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .encapsulated, boundaryKey: boundary))\n            expectedData.append(Data((\n                \"Content-Type: image/jpeg\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"rainbow\\\"; filename=\\\"rainbow.jpg\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedData.append(try! Data(contentsOf: rainbowImageURL))\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .final, boundaryKey: boundary))\n\n            // XCTAssertEqual(encodedData, expectedData, \"data should match expected data\")\n            XCTAssertEqual(encodedData.count, expectedData.count)\n        }\n    }\n\n    func testEncodingStreamBodyPart() {\n        // Given\n        let multipartFormData = CLDNMultipartFormData()\n\n        let unicornImageURL = url(forResource: \"unicorn\", withExtension: \"png\")\n        let unicornDataLength = UInt64((try! Data(contentsOf: unicornImageURL)).count)\n        let unicornStream = InputStream(url: unicornImageURL)!\n\n        multipartFormData.append(\n            unicornStream,\n            withLength: unicornDataLength,\n            name: \"unicorn\",\n            fileName: \"unicorn.png\",\n            mimeType: \"image/png\"\n        )\n\n        var encodedData: Data?\n\n        // When\n        do {\n            encodedData = try multipartFormData.encode()\n        } catch {\n            // No-op\n        }\n\n        // Then\n        XCTAssertNotNil(encodedData, \"encoded data should not be nil\")\n\n        if let encodedData = encodedData {\n            let boundary = multipartFormData.boundary\n\n            var expectedData = Data()\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .initial, boundaryKey: boundary))\n            expectedData.append(Data((\n                \"Content-Type: image/png\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"unicorn\\\"; filename=\\\"unicorn.png\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedData.append(try! Data(contentsOf: unicornImageURL))\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .final, boundaryKey: boundary))\n\n            // XCTAssertEqual(encodedData, expectedData, \"data should match expected data\")\n            XCTAssertEqual(encodedData.count, expectedData.count)\n        }\n    }\n\n    func testEncodingMultipleStreamBodyParts() {\n        // Given\n        let multipartFormData = CLDNMultipartFormData()\n\n        let unicornImageURL = url(forResource: \"unicorn\", withExtension: \"png\")\n        let unicornDataLength = UInt64((try! Data(contentsOf: unicornImageURL)).count)\n        let unicornStream = InputStream(url: unicornImageURL)!\n\n        let rainbowImageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n        let rainbowDataLength = UInt64((try! Data(contentsOf: rainbowImageURL)).count)\n        let rainbowStream = InputStream(url: rainbowImageURL)!\n\n        multipartFormData.append(\n            unicornStream,\n            withLength: unicornDataLength,\n            name: \"unicorn\",\n            fileName: \"unicorn.png\",\n            mimeType: \"image/png\"\n        )\n        multipartFormData.append(\n            rainbowStream,\n            withLength: rainbowDataLength,\n            name: \"rainbow\",\n            fileName: \"rainbow.jpg\",\n            mimeType: \"image/jpeg\"\n        )\n\n        var encodedData: Data?\n\n        // When\n        do {\n            encodedData = try multipartFormData.encode()\n        } catch {\n            // No-op\n        }\n\n        // Then\n        XCTAssertNotNil(encodedData, \"encoded data should not be nil\")\n\n        if let encodedData = encodedData {\n            let boundary = multipartFormData.boundary\n\n            var expectedData = Data()\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .initial, boundaryKey: boundary))\n            expectedData.append(Data((\n                \"Content-Type: image/png\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"unicorn\\\"; filename=\\\"unicorn.png\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedData.append(try! Data(contentsOf: unicornImageURL))\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .encapsulated, boundaryKey: boundary))\n            expectedData.append(Data((\n                \"Content-Type: image/jpeg\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"rainbow\\\"; filename=\\\"rainbow.jpg\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedData.append(try! Data(contentsOf: rainbowImageURL))\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .final, boundaryKey: boundary))\n\n            // XCTAssertEqual(encodedData, expectedData, \"data should match expected data\")\n            XCTAssertEqual(encodedData.count, expectedData.count)\n        }\n    }\n\n    func testEncodingMultipleBodyPartsWithVaryingTypes() {\n        // Given\n        let multipartFormData = CLDNMultipartFormData()\n\n        let loremData = Data(\"Lorem ipsum.\".utf8)\n\n        let unicornImageURL = url(forResource: \"unicorn\", withExtension: \"png\")\n\n        let rainbowImageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n        let rainbowDataLength = UInt64((try! Data(contentsOf: rainbowImageURL)).count)\n        let rainbowStream = InputStream(url: rainbowImageURL)!\n\n        multipartFormData.append(loremData, withName: \"lorem\")\n        multipartFormData.append(unicornImageURL, withName: \"unicorn\")\n        multipartFormData.append(\n            rainbowStream,\n            withLength: rainbowDataLength,\n            name: \"rainbow\",\n            fileName: \"rainbow.jpg\",\n            mimeType: \"image/jpeg\"\n        )\n\n        var encodedData: Data?\n\n        // When\n        do {\n            encodedData = try multipartFormData.encode()\n        } catch {\n            // No-op\n        }\n\n        // Then\n        XCTAssertNotNil(encodedData, \"encoded data should not be nil\")\n\n        if let encodedData = encodedData {\n            let boundary = multipartFormData.boundary\n\n            var expectedData = Data()\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .initial, boundaryKey: boundary))\n            expectedData.append(Data(\n                \"Content-Disposition: form-data; name=\\\"lorem\\\"\\(crlf)\\(crlf)\".utf8\n                )\n            )\n            expectedData.append(loremData)\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .encapsulated, boundaryKey: boundary))\n            expectedData.append(Data((\n                \"Content-Type: image/png\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"unicorn\\\"; filename=\\\"unicorn.png\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedData.append(try! Data(contentsOf: unicornImageURL))\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .encapsulated, boundaryKey: boundary))\n            expectedData.append(Data((\n                \"Content-Type: image/jpeg\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"rainbow\\\"; filename=\\\"rainbow.jpg\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedData.append(try! Data(contentsOf: rainbowImageURL))\n            expectedData.append(BoundaryGenerator.boundaryData(boundaryType: .final, boundaryKey: boundary))\n\n            // XCTAssertEqual(encodedData, expectedData, \"data should match expected data\")\n            XCTAssertEqual(encodedData.count, expectedData.count)\n        }\n    }\n}\n\n// MARK: -\n\nclass MultipartFormDataWriteEncodedDataToDiskTestCase: BaseTestCase {\n    let crlf = EncodingCharacters.crlf\n\n    func testWritingEncodedDataBodyPartToDisk() {\n        // Given\n        let fileURL = temporaryFileURL()\n        let multipartFormData = CLDNMultipartFormData()\n\n        let data = \"Lorem ipsum dolor sit amet.\".data(using: .utf8, allowLossyConversion: false)!\n        multipartFormData.append(data, withName: \"data\")\n\n        var encodingError: Error?\n\n        // When\n        do {\n            try multipartFormData.writeEncodedData(to: fileURL)\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNil(encodingError, \"encoding error should be nil\")\n\n        if let fileData = try? Data(contentsOf: fileURL) {\n            let boundary = multipartFormData.boundary\n\n            let expectedFileData = (\n                BoundaryGenerator.boundary(forBoundaryType: .initial, boundaryKey: boundary) +\n                \"Content-Disposition: form-data; name=\\\"data\\\"\\(crlf)\\(crlf)\" +\n                \"Lorem ipsum dolor sit amet.\" +\n                BoundaryGenerator.boundary(forBoundaryType: .final, boundaryKey: boundary)\n            ).data(using: .utf8, allowLossyConversion: false)!\n\n            XCTAssertEqual(fileData, expectedFileData, \"file data should match expected file data\")\n        } else {\n            XCTFail(\"file data should not be nil\")\n        }\n    }\n\n    func testWritingMultipleEncodedDataBodyPartsToDisk() {\n        // Given\n        let fileURL = temporaryFileURL()\n        let multipartFormData = CLDNMultipartFormData()\n\n        let frenchData = \"français\".data(using: .utf8, allowLossyConversion: false)!\n        let japaneseData = \"日本語\".data(using: .utf8, allowLossyConversion: false)!\n        let emojiData = \"😃👍🏻🍻🎉\".data(using: .utf8, allowLossyConversion: false)!\n\n        multipartFormData.append(frenchData, withName: \"french\")\n        multipartFormData.append(japaneseData, withName: \"japanese\")\n        multipartFormData.append(emojiData, withName: \"emoji\")\n\n        var encodingError: Error?\n\n        // When\n        do {\n            try multipartFormData.writeEncodedData(to: fileURL)\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNil(encodingError, \"encoding error should be nil\")\n\n        if let fileData = try? Data(contentsOf: fileURL) {\n            let boundary = multipartFormData.boundary\n\n            let expectedFileData = (\n                BoundaryGenerator.boundary(forBoundaryType: .initial, boundaryKey: boundary) +\n                \"Content-Disposition: form-data; name=\\\"french\\\"\\(crlf)\\(crlf)\" +\n                \"français\" +\n                BoundaryGenerator.boundary(forBoundaryType: .encapsulated, boundaryKey: boundary) +\n                \"Content-Disposition: form-data; name=\\\"japanese\\\"\\(crlf)\\(crlf)\" +\n                \"日本語\" +\n                BoundaryGenerator.boundary(forBoundaryType: .encapsulated, boundaryKey: boundary) +\n                \"Content-Disposition: form-data; name=\\\"emoji\\\"\\(crlf)\\(crlf)\" +\n                \"😃👍🏻🍻🎉\" +\n                BoundaryGenerator.boundary(forBoundaryType: .final, boundaryKey: boundary)\n            ).data(using: .utf8, allowLossyConversion: false)!\n\n            XCTAssertEqual(fileData, expectedFileData, \"file data should match expected file data\")\n        } else {\n            XCTFail(\"file data should not be nil\")\n        }\n    }\n\n    func testWritingEncodedFileBodyPartToDisk() {\n        // Given\n        let fileURL = temporaryFileURL()\n        let multipartFormData = CLDNMultipartFormData()\n\n        let unicornImageURL = url(forResource: \"unicorn\", withExtension: \"png\")\n        multipartFormData.append(unicornImageURL, withName: \"unicorn\")\n\n        var encodingError: Error?\n\n        // When\n        do {\n            try multipartFormData.writeEncodedData(to: fileURL)\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNil(encodingError, \"encoding error should be nil\")\n\n        if let fileData = try? Data(contentsOf: fileURL) {\n            let boundary = multipartFormData.boundary\n\n            var expectedFileData = Data()\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .initial, boundaryKey: boundary))\n            expectedFileData.append(Data((\n                \"Content-Type: image/png\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"unicorn\\\"; filename=\\\"unicorn.png\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedFileData.append(try! Data(contentsOf: unicornImageURL))\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .final, boundaryKey: boundary))\n\n            // XCTAssertEqual(fileData, expectedFileData, \"file data should match expected file data\")\n            XCTAssertEqual(fileData.count, expectedFileData.count)\n        } else {\n            XCTFail(\"file data should not be nil\")\n        }\n    }\n\n    func testWritingMultipleEncodedFileBodyPartsToDisk() {\n        // Given\n        let fileURL = temporaryFileURL()\n        let multipartFormData = CLDNMultipartFormData()\n\n        let unicornImageURL = url(forResource: \"unicorn\", withExtension: \"png\")\n        let rainbowImageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n\n        multipartFormData.append(unicornImageURL, withName: \"unicorn\")\n        multipartFormData.append(rainbowImageURL, withName: \"rainbow\")\n\n        var encodingError: Error?\n\n        // When\n        do {\n            try multipartFormData.writeEncodedData(to: fileURL)\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNil(encodingError, \"encoding error should be nil\")\n\n        if let fileData = try? Data(contentsOf: fileURL) {\n            let boundary = multipartFormData.boundary\n\n            var expectedFileData = Data()\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .initial, boundaryKey: boundary))\n            expectedFileData.append(Data((\n                \"Content-Type: image/png\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"unicorn\\\"; filename=\\\"unicorn.png\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedFileData.append(try! Data(contentsOf: unicornImageURL))\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .encapsulated, boundaryKey: boundary))\n            expectedFileData.append(Data((\n                \"Content-Type: image/jpeg\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"rainbow\\\"; filename=\\\"rainbow.jpg\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedFileData.append(try! Data(contentsOf: rainbowImageURL))\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .final, boundaryKey: boundary))\n\n            // XCTAssertEqual(fileData, expectedFileData, \"file data should match expected file data\")\n            XCTAssertEqual(fileData.count, expectedFileData.count)\n        } else {\n            XCTFail(\"file data should not be nil\")\n        }\n    }\n\n    func testWritingEncodedStreamBodyPartToDisk() {\n        // Given\n        let fileURL = temporaryFileURL()\n        let multipartFormData = CLDNMultipartFormData()\n\n        let unicornImageURL = url(forResource: \"unicorn\", withExtension: \"png\")\n        let unicornDataLength = UInt64((try! Data(contentsOf: unicornImageURL)).count)\n        let unicornStream = InputStream(url: unicornImageURL)!\n\n        multipartFormData.append(\n            unicornStream,\n            withLength: unicornDataLength,\n            name: \"unicorn\",\n            fileName: \"unicorn.png\",\n            mimeType: \"image/png\"\n        )\n\n        var encodingError: Error?\n\n        // When\n        do {\n            try multipartFormData.writeEncodedData(to: fileURL)\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNil(encodingError, \"encoding error should be nil\")\n\n        if let fileData = try? Data(contentsOf: fileURL) {\n            let boundary = multipartFormData.boundary\n\n            var expectedFileData = Data()\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .initial, boundaryKey: boundary))\n            expectedFileData.append(Data((\n                \"Content-Type: image/png\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"unicorn\\\"; filename=\\\"unicorn.png\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedFileData.append(try! Data(contentsOf: unicornImageURL))\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .final, boundaryKey: boundary))\n\n            // XCTAssertEqual(fileData, expectedFileData, \"file data should match expected file data\")\n            XCTAssertEqual(fileData.count, expectedFileData.count)\n        } else {\n            XCTFail(\"file data should not be nil\")\n        }\n    }\n\n    func testWritingMultipleEncodedStreamBodyPartsToDisk() {\n        // Given\n        let fileURL = temporaryFileURL()\n        let multipartFormData = CLDNMultipartFormData()\n\n        let unicornImageURL = url(forResource: \"unicorn\", withExtension: \"png\")\n        let unicornDataLength = UInt64((try! Data(contentsOf: unicornImageURL)).count)\n        let unicornStream = InputStream(url: unicornImageURL)!\n\n        let rainbowImageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n        let rainbowDataLength = UInt64((try! Data(contentsOf: rainbowImageURL)).count)\n        let rainbowStream = InputStream(url: rainbowImageURL)!\n\n        multipartFormData.append(\n            unicornStream,\n            withLength: unicornDataLength,\n            name: \"unicorn\",\n            fileName: \"unicorn.png\",\n            mimeType: \"image/png\"\n        )\n        multipartFormData.append(\n            rainbowStream,\n            withLength: rainbowDataLength,\n            name: \"rainbow\",\n            fileName: \"rainbow.jpg\",\n            mimeType: \"image/jpeg\"\n        )\n\n\n        var encodingError: Error?\n\n        // When\n        do {\n            try multipartFormData.writeEncodedData(to: fileURL)\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNil(encodingError, \"encoding error should be nil\")\n\n        if let fileData = try? Data(contentsOf: fileURL) {\n            let boundary = multipartFormData.boundary\n\n            var expectedFileData = Data()\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .initial, boundaryKey: boundary))\n            expectedFileData.append(Data((\n                \"Content-Type: image/png\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"unicorn\\\"; filename=\\\"unicorn.png\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedFileData.append(try! Data(contentsOf: unicornImageURL))\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .encapsulated, boundaryKey: boundary))\n            expectedFileData.append(Data((\n                \"Content-Type: image/jpeg\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"rainbow\\\"; filename=\\\"rainbow.jpg\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedFileData.append(try! Data(contentsOf: rainbowImageURL))\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .final, boundaryKey: boundary))\n\n            // XCTAssertEqual(fileData, expectedFileData, \"file data should match expected file data\")\n            XCTAssertEqual(fileData.count, expectedFileData.count)\n        } else {\n            XCTFail(\"file data should not be nil\")\n        }\n    }\n\n    func testWritingMultipleEncodedBodyPartsWithVaryingTypesToDisk() {\n        // Given\n        let fileURL = temporaryFileURL()\n        let multipartFormData = CLDNMultipartFormData()\n\n        let loremData = Data(\"Lorem ipsum.\".utf8)\n\n        let unicornImageURL = url(forResource: \"unicorn\", withExtension: \"png\")\n\n        let rainbowImageURL = url(forResource: \"rainbow\", withExtension: \"jpg\")\n        let rainbowDataLength = UInt64((try! Data(contentsOf: rainbowImageURL)).count)\n        let rainbowStream = InputStream(url: rainbowImageURL)!\n\n        multipartFormData.append(loremData, withName: \"lorem\")\n        multipartFormData.append(unicornImageURL, withName: \"unicorn\")\n        multipartFormData.append(\n            rainbowStream,\n            withLength: rainbowDataLength,\n            name: \"rainbow\",\n            fileName: \"rainbow.jpg\",\n            mimeType: \"image/jpeg\"\n        )\n\n        var encodingError: Error?\n\n        // When\n        do {\n            try multipartFormData.writeEncodedData(to: fileURL)\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNil(encodingError, \"encoding error should be nil\")\n\n        if let fileData = try? Data(contentsOf: fileURL) {\n            let boundary = multipartFormData.boundary\n\n            var expectedFileData = Data()\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .initial, boundaryKey: boundary))\n            expectedFileData.append(Data(\n                \"Content-Disposition: form-data; name=\\\"lorem\\\"\\(crlf)\\(crlf)\".utf8\n                )\n            )\n            expectedFileData.append(loremData)\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .encapsulated, boundaryKey: boundary))\n            expectedFileData.append(Data((\n                \"Content-Type: image/png\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"unicorn\\\"; filename=\\\"unicorn.png\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedFileData.append(try! Data(contentsOf: unicornImageURL))\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .encapsulated, boundaryKey: boundary))\n            expectedFileData.append(Data((\n                \"Content-Type: image/jpeg\\(crlf)\" +\n                \"Content-Disposition: form-data; name=\\\"rainbow\\\"; filename=\\\"rainbow.jpg\\\"\\(crlf)\\(crlf)\").utf8\n                )\n            )\n            expectedFileData.append(try! Data(contentsOf: rainbowImageURL))\n            expectedFileData.append(BoundaryGenerator.boundaryData(boundaryType: .final, boundaryKey: boundary))\n\n            // XCTAssertEqual(fileData, expectedFileData, \"file data should match expected file data\")\n            XCTAssertEqual(fileData.count, expectedFileData.count)\n        } else {\n            XCTFail(\"file data should not be nil\")\n        }\n    }\n}\n\n// MARK: -\n\nclass MultipartFormDataFailureTestCase: BaseTestCase {\n    func testThatAppendingFileBodyPartWithInvalidLastPathComponentReturnsError() {\n        // Given\n        let fileURL = NSURL(string: \"\")! as URL\n        let multipartFormData = CLDNMultipartFormData()\n        multipartFormData.append(fileURL, withName: \"empty_data\")\n\n        var encodingError: Error?\n\n        // When\n        do {\n            _ = try multipartFormData.encode()\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNotNil(encodingError, \"encoding error should not be nil\")\n\n        if let error = encodingError as? CLDNError {\n            XCTAssertTrue(error.isBodyPartFilenameInvalid)\n\n            let expectedFailureReason = \"The URL provided does not have a valid filename: \\(fileURL)\"\n            XCTAssertEqual(error.localizedDescription, expectedFailureReason, \"failure reason does not match expected value\")\n        } else {\n            XCTFail(\"Error should be CLDNError.\")\n        }\n    }\n\n    func testThatAppendingFileBodyPartThatIsNotFileURLReturnsError() {\n        // Given\n        let fileURL = URL(string: \"https://example.com/image.jpg\")!\n        let multipartFormData = CLDNMultipartFormData()\n        multipartFormData.append(fileURL, withName: \"empty_data\")\n\n        var encodingError: Error?\n\n        // When\n        do {\n            _ = try multipartFormData.encode()\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNotNil(encodingError, \"encoding error should not be nil\")\n\n        if let error = encodingError as? CLDNError {\n            XCTAssertTrue(error.isBodyPartURLInvalid)\n\n            let expectedFailureReason = \"The URL provided is not a file URL: \\(fileURL)\"\n            XCTAssertEqual(error.localizedDescription, expectedFailureReason, \"error failure reason does not match expected value\")\n        } else {\n            XCTFail(\"Error should be CLDNError.\")\n        }\n    }\n\n    func testThatAppendingFileBodyPartThatIsNotReachableReturnsError() {\n        // Given\n        let filePath = (NSTemporaryDirectory() as NSString).appendingPathComponent(\"does_not_exist.jpg\")\n        let fileURL = URL(fileURLWithPath: filePath)\n        let multipartFormData = CLDNMultipartFormData()\n        multipartFormData.append(fileURL, withName: \"empty_data\")\n\n        var encodingError: Error?\n\n        // When\n        do {\n            _ = try multipartFormData.encode()\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNotNil(encodingError, \"encoding error should not be nil\")\n\n        if let error = encodingError as? CLDNError {\n            XCTAssertTrue(error.isBodyPartFileNotReachableWithError)\n        } else {\n            XCTFail(\"Error should be CLDNError.\")\n        }\n    }\n\n    func testThatAppendingFileBodyPartThatIsDirectoryReturnsError() {\n        // Given\n        let directoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)\n        let multipartFormData = CLDNMultipartFormData()\n        multipartFormData.append(directoryURL, withName: \"empty_data\", fileName: \"empty\", mimeType: \"application/octet\")\n\n        var encodingError: Error?\n\n        // When\n        do {\n            _ = try multipartFormData.encode()\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNotNil(encodingError, \"encoding error should not be nil\")\n\n        if let error = encodingError as? CLDNError {\n            XCTAssertTrue(error.isBodyPartFileIsDirectory)\n\n            let expectedFailureReason = \"The URL provided is a directory: \\(directoryURL)\"\n            XCTAssertEqual(error.localizedDescription, expectedFailureReason, \"error failure reason does not match expected value\")\n        } else {\n            XCTFail(\"Error should be CLDNError.\")\n        }\n    }\n\n    func testThatWritingEncodedDataToExistingFileURLFails() {\n        // Given\n        let fileURL = temporaryFileURL()\n\n        var writerError: Error?\n\n        do {\n            try \"dummy data\".write(to: fileURL, atomically: true, encoding: String.Encoding.utf8)\n        } catch {\n            writerError = error\n        }\n\n        let multipartFormData = CLDNMultipartFormData()\n        let data = \"Lorem ipsum dolor sit amet.\".data(using: .utf8, allowLossyConversion: false)!\n        multipartFormData.append(data, withName: \"data\")\n\n        var encodingError: Error?\n\n        // When\n        do {\n            try multipartFormData.writeEncodedData(to: fileURL)\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNil(writerError, \"writer error should be nil\")\n        XCTAssertNotNil(encodingError, \"encoding error should not be nil\")\n\n        if let encodingError = encodingError as? CLDNError {\n            XCTAssertTrue(encodingError.isOutputStreamFileAlreadyExists)\n        }\n    }\n\n    func testThatWritingEncodedDataToBadURLFails() {\n        // Given\n        let fileURL = URL(string: \"/this/is/not/a/valid/url\")!\n\n        let multipartFormData = CLDNMultipartFormData()\n        let data = \"Lorem ipsum dolor sit amet.\".data(using: .utf8, allowLossyConversion: false)!\n        multipartFormData.append(data, withName: \"data\")\n\n        var encodingError: Error?\n\n        // When\n        do {\n            try multipartFormData.writeEncodedData(to: fileURL)\n        } catch {\n            encodingError = error\n        }\n\n        // Then\n        XCTAssertNotNil(encodingError, \"encoding error should not be nil\")\n\n        if let encodingError = encodingError as? CLDNError {\n            XCTAssertTrue(encodingError.isOutputStreamURLInvalid)\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Features/ResponseSerializationTests.swift",
    "content": "//\n//  ResponseSerializationTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nprivate func httpURLResponse(forStatusCode statusCode: Int, headers: CLDNHTTPHeaders = [:]) -> HTTPURLResponse {\n    let url = URL(string: \"https://httpbin.org/get\")!\n    return HTTPURLResponse(url: url, statusCode: statusCode, httpVersion: \"HTTP/1.1\", headerFields: headers)!\n}\n\n// MARK: -\n\nclass DataResponseSerializationTestCase: BaseTestCase {\n\n    // MARK: Properties\n\n    private let error = CLDNError.responseSerializationFailed(reason: .inputDataNil)\n\n    // MARK: Tests - Data Response Serializer\n\n    func testThatDataResponseSerializerSucceedsWhenDataIsNotNil() {\n        // Given\n        let serializer = CLDNDataRequest.dataResponseSerializer()\n        let data = \"data\".data(using: .utf8)!\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, data, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n    }\n\n    func testThatDataResponseSerializerFailsWhenDataIsNil() {\n        // Given\n        let serializer = CLDNDataRequest.dataResponseSerializer()\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNil)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatDataResponseSerializerFailsWhenErrorIsNotNil() {\n        // Given\n        let serializer = CLDNDataRequest.dataResponseSerializer()\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, nil, error)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNil)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatDataResponseSerializerFailsWhenDataIsNilWithNonEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.dataResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 200)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure, \"result is failure should be true\")\n        XCTAssertNil(result.value, \"result value should be nil\")\n        XCTAssertNotNil(result.error, \"result error should not be nil\")\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNil)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatDataResponseSerializerSucceedsWhenDataIsNilWithEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.dataResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 204)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n\n        if let data = result.value {\n            XCTAssertEqual(data.count, 0)\n        }\n    }\n\n    // MARK: Tests - String Response Serializer\n\n    func testThatStringResponseSerializerFailsWhenDataIsNil() {\n        // Given\n        let serializer = CLDNDataRequest.stringResponseSerializer()\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNil)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatStringResponseSerializerSucceedsWhenDataIsEmpty() {\n        // Given\n        let serializer = CLDNDataRequest.stringResponseSerializer()\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, Data(), nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n    }\n\n    func testThatStringResponseSerializerSucceedsWithUTF8DataAndNoProvidedEncoding() {\n        let serializer = CLDNDataRequest.stringResponseSerializer()\n        let data = \"data\".data(using: .utf8)!\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, data, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n    }\n\n    func testThatStringResponseSerializerSucceedsWithUTF8DataAndUTF8ProvidedEncoding() {\n        let serializer = CLDNDataRequest.stringResponseSerializer(encoding: .utf8)\n        let data = \"data\".data(using: .utf8)!\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, data, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n    }\n\n    func testThatStringResponseSerializerSucceedsWithUTF8DataUsingResponseTextEncodingName() {\n        let serializer = CLDNDataRequest.stringResponseSerializer()\n        let data = \"data\".data(using: .utf8)!\n        let response = httpURLResponse(forStatusCode: 200, headers: [\"Content-Type\": \"image/jpeg; charset=utf-8\"])\n\n        // When\n        let result = serializer.serializeResponse(nil, response, data, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n    }\n\n    func testThatStringResponseSerializerFailsWithUTF32DataAndUTF8ProvidedEncoding() {\n        // Given\n        let serializer = CLDNDataRequest.stringResponseSerializer(encoding: .utf8)\n        let data = \"random data\".data(using: .utf32)!\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, data, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError, let failedEncoding = error.failedStringEncoding {\n            XCTAssertTrue(error.isStringSerializationFailed)\n            XCTAssertEqual(failedEncoding, .utf8)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatStringResponseSerializerFailsWithUTF32DataAndUTF8ResponseEncoding() {\n        // Given\n        let serializer = CLDNDataRequest.stringResponseSerializer()\n        let data = \"random data\".data(using: .utf32)!\n        let response = httpURLResponse(forStatusCode: 200, headers: [\"Content-Type\": \"image/jpeg; charset=utf-8\"])\n\n        // When\n        let result = serializer.serializeResponse(nil, response, data, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError, let failedEncoding = error.failedStringEncoding {\n            XCTAssertTrue(error.isStringSerializationFailed)\n            XCTAssertEqual(failedEncoding, .utf8)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatStringResponseSerializerFailsWhenErrorIsNotNil() {\n        // Given\n        let serializer = CLDNDataRequest.stringResponseSerializer()\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, nil, error)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNil)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatStringResponseSerializerFailsWhenDataIsNilWithNonEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.stringResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 200)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNil)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatStringResponseSerializerSucceedsWhenDataIsNilWithEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.stringResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 205)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n\n        if let string = result.value {\n            XCTAssertEqual(string, \"\")\n        }\n    }\n\n    // MARK: Tests - JSON Response Serializer\n\n    func testThatJSONResponseSerializerFailsWhenDataIsNil() {\n        // Given\n        let serializer = CLDNDataRequest.jsonResponseSerializer()\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNilOrZeroLength)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatJSONResponseSerializerFailsWhenDataIsEmpty() {\n        // Given\n        let serializer = CLDNDataRequest.jsonResponseSerializer()\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, Data(), nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNilOrZeroLength)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatJSONResponseSerializerSucceedsWhenDataIsValidJSON() {\n        // Given\n        let serializer = CLDNDataRequest.jsonResponseSerializer()\n        let data = \"{\\\"json\\\": true}\".data(using: .utf8)!\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, data, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n    }\n\n    func testThatJSONResponseSerializerFailsWhenDataIsInvalidJSON() {\n        // Given\n        let serializer = CLDNDataRequest.jsonResponseSerializer()\n        let data = \"definitely not valid json\".data(using: .utf8)!\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, data, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError, let underlyingError = error.underlyingError as? CocoaError {\n            XCTAssertTrue(error.isJSONSerializationFailed)\n            XCTAssertEqual(underlyingError.errorCode, 3840)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatJSONResponseSerializerFailsWhenErrorIsNotNil() {\n        // Given\n        let serializer = CLDNDataRequest.jsonResponseSerializer()\n\n        // When\n        let result = serializer.serializeResponse(nil, nil, nil, error)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNil)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatJSONResponseSerializerFailsWhenDataIsNilWithNonEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.jsonResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 200)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNilOrZeroLength)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatJSONResponseSerializerSucceedsWhenDataIsNilWithEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.jsonResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 204)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n\n        if let json = result.value as? NSNull {\n            XCTAssertEqual(json, NSNull())\n        }\n    }\n}\n\n// MARK: -\n\nclass DownloadResponseSerializationTestCase: BaseTestCase {\n\n    // MARK: Properties\n\n    private let error = CLDNError.responseSerializationFailed(reason: .inputFileNil)\n\n    private var jsonEmptyDataFileURL: URL { return url(forResource: \"empty_data\", withExtension: \"json\") }\n    private var jsonValidDataFileURL: URL { return url(forResource: \"valid_data\", withExtension: \"json\") }\n    private var jsonInvalidDataFileURL: URL { return url(forResource: \"invalid_data\", withExtension: \"json\") }\n\n    private var plistEmptyDataFileURL: URL { return url(forResource: \"empty\", withExtension: \"data\") }\n    private var plistValidDataFileURL: URL { return url(forResource: \"valid\", withExtension: \"data\") }\n    private var plistInvalidDataFileURL: URL { return url(forResource: \"invalid\", withExtension: \"data\") }\n\n    private var stringEmptyDataFileURL: URL { return url(forResource: \"empty_string\", withExtension: \"txt\") }\n    private var stringUTF8DataFileURL: URL { return url(forResource: \"utf8_string\", withExtension: \"txt\") }\n    private var stringUTF32DataFileURL: URL { return url(forResource: \"utf32_string\", withExtension: \"txt\") }\n\n    private var invalidFileURL: URL { return URL(fileURLWithPath: \"/this/file/does/not/exist.txt\") }\n\n    // MARK: Tests - Data Response Serializer\n\n    func testThatDataResponseSerializerSucceedsWhenDataIsNilWithEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.dataResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 205)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n\n        if let data = result.value {\n            XCTAssertEqual(data.count, 0)\n        }\n    }\n\n    // MARK: Tests - String Response Serializer\n\n    func testThatStringResponseSerializerFailsWhenDataIsNilWithNonEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.stringResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 200)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNil)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatStringResponseSerializerSucceedsWhenDataIsNilWithEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.stringResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 204)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n\n        if let string = result.value {\n            XCTAssertEqual(string, \"\")\n        }\n    }\n\n    // MARK: Tests - JSON Response Serializer\n\n    func testThatJSONResponseSerializerFailsWhenDataIsNilWithNonEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.jsonResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 200)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isFailure)\n        XCTAssertNil(result.value)\n        XCTAssertNotNil(result.error)\n\n        if let error = result.error as? CLDNError {\n            XCTAssertTrue(error.isInputDataNilOrZeroLength)\n        } else {\n            XCTFail(\"error should not be nil\")\n        }\n    }\n\n    func testThatJSONResponseSerializerSucceedsWhenDataIsNilWithEmptyResponseStatusCode() {\n        // Given\n        let serializer = CLDNDataRequest.jsonResponseSerializer()\n        let response = httpURLResponse(forStatusCode: 205)\n\n        // When\n        let result = serializer.serializeResponse(nil, response, nil, nil)\n\n        // Then\n        XCTAssertTrue(result.isSuccess)\n        XCTAssertNotNil(result.value)\n        XCTAssertNil(result.error)\n\n        if let json = result.value as? NSNull {\n            XCTAssertEqual(json, NSNull())\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Features/URLProtocolTests.swift",
    "content": "//\n//  URLProtocolTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass ProxyURLProtocol: URLProtocol {\n\n    // MARK: Properties\n\n    struct PropertyKeys {\n        static let handledByForwarderURLProtocol = \"HandledByProxyURLProtocol\"\n    }\n\n    lazy var session: URLSession = {\n        let configuration: URLSessionConfiguration = {\n            let configuration = URLSessionConfiguration.ephemeral\n            configuration.httpAdditionalHeaders = CLDNSessionManager.defaultHTTPHeaders\n\n            return configuration\n        }()\n\n        let session = Foundation.URLSession(configuration: configuration, delegate: self, delegateQueue: nil)\n\n        return session\n    }()\n\n    var activeTask: URLSessionTask?\n\n    // MARK: Class Request Methods\n\n    override class func canInit(with request: URLRequest) -> Bool {\n        if URLProtocol.property(forKey: PropertyKeys.handledByForwarderURLProtocol, in: request) != nil {\n            return false\n        }\n\n        return true\n    }\n\n    override class func canonicalRequest(for request: URLRequest) -> URLRequest {\n        if let headers = request.allHTTPHeaderFields {\n            do {\n                return try CLDNURLEncoding.default.CLDN_Encode(request, with: headers)\n            } catch {\n                return request\n            }\n        }\n\n        return request\n    }\n\n    override class func requestIsCacheEquivalent(_ a: URLRequest, to b: URLRequest) -> Bool {\n        return false\n    }\n\n    // MARK: Loading Methods\n\n    override func startLoading() {\n        // rdar://26849668 - URLProtocol had some API's that didnt make the value type conversion\n        let urlRequest = (request.urlRequest! as NSURLRequest).mutableCopy() as! NSMutableURLRequest\n        URLProtocol.setProperty(true, forKey: PropertyKeys.handledByForwarderURLProtocol, in: urlRequest)\n        activeTask = session.dataTask(with: urlRequest as URLRequest)\n        activeTask?.resume()\n    }\n\n    override func stopLoading() {\n        activeTask?.cancel()\n    }\n}\n\n// MARK: -\n\nextension ProxyURLProtocol: URLSessionDataDelegate {\n\n    // MARK: NSURLSessionDelegate\n\n    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {\n        client?.urlProtocol(self, didLoad: data)\n    }\n\n    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {\n        if let response = task.response {\n            client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)\n        }\n\n        client?.urlProtocolDidFinishLoading(self)\n    }\n}\n\n// MARK: -\n\nclass URLProtocolTestCase: BaseTestCase {\n    var manager: CLDNSessionManager!\n\n    // MARK: Setup and Teardown\n\n    override func setUp() {\n        super.setUp()\n\n        manager = {\n            let configuration: URLSessionConfiguration = {\n                let configuration = URLSessionConfiguration.default\n                configuration.protocolClasses = [ProxyURLProtocol.self]\n                configuration.httpAdditionalHeaders = [\"Session-Configuration-Header\": \"foo\"]\n\n                return configuration\n            }()\n\n            return CLDNSessionManager(configuration: configuration)\n        }()\n    }\n\n    // MARK: Tests\n\n    func skipped_testThatURLProtocolReceivesRequestHeadersAndSessionConfigurationHeaders() {\n        // Given\n        let urlString = \"https://httpbin.org/headers\"\n        let url = URL(string: urlString)!\n\n        var urlRequest = URLRequest(url: url)\n        urlRequest.httpMethod = CLDNHTTPMethod.get.rawValue\n        urlRequest.setValue(\"foobar\", forHTTPHeaderField: \"request-header\")\n\n        let expectation = self.expectation(description: \"GET request should succeed\")\n\n        var response: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlRequest)\n            .response { resp in\n                response = resp\n                expectation.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(response?.request)\n        XCTAssertNotNil(response?.response)\n        XCTAssertNotNil(response?.data)\n        XCTAssertNil(response?.error)\n\n        if let headers = response?.response?.allHeaderFields as? [String: String] {\n            XCTAssertEqual(headers[\"request-header\"], \"foobar\")\n\n            // Configuration headers are only passed in on iOS 9.0+\n            if #available(iOS 9.0, *) {\n                XCTAssertEqual(headers[\"session-configuration-header\"], \"foo\")\n            } else {\n                XCTAssertNil(headers[\"session-configuration-header\"])\n            }\n        } else {\n            XCTFail(\"headers should not be nil\")\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Features/ValidationTests.swift",
    "content": "//\n//  ValidationTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass StatusCodeValidationTestCase: BaseTestCase {\n    func testThatValidationForRequestWithAcceptableStatusCodeResponseSucceeds() {\n        // Given\n        let urlString = \"https://httpbin.org/status/200\"\n\n        let expectation1 = self.expectation(description: \"request should return 200 status code\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(statusCode: 200..<300)\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(requestError)\n    }\n\n    func testThatValidationForRequestWithUnacceptableStatusCodeResponseFails() {\n        // Given\n        let urlString = \"https://httpbin.org/status/404\"\n\n        let expectation1 = self.expectation(description: \"request should return 404 status code\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(statusCode: [200])\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(requestError)\n\n        for error in [requestError] {\n            if let error = error as? CLDNError, let statusCode = error.responseCode {\n                XCTAssertTrue(error.isUnacceptableStatusCode)\n                XCTAssertEqual(statusCode, 404)\n            } else {\n                XCTFail(\"Error should not be nil, should be an CLDNError, and should have an associated statusCode.\")\n            }\n        }\n    }\n\n    func testThatValidationForRequestWithNoAcceptableStatusCodesFails() {\n        // Given\n        let urlString = \"https://httpbin.org/status/201\"\n\n        let expectation1 = self.expectation(description: \"request should return 201 status code\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(statusCode: [])\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(requestError)\n\n        for error in [requestError] {\n            if let error = error as? CLDNError, let statusCode = error.responseCode {\n                XCTAssertTrue(error.isUnacceptableStatusCode)\n                XCTAssertEqual(statusCode, 201)\n            } else {\n                XCTFail(\"Error should not be nil, should be an CLDNError, and should have an associated statusCode.\")\n            }\n        }\n    }\n}\n\n// MARK: -\n\nclass ContentTypeValidationTestCase: BaseTestCase {\n    func testThatValidationForRequestWithAcceptableContentTypeResponseSucceeds() {\n        // Given\n        let urlString = \"https://httpbin.org/ip\"\n\n        let expectation1 = self.expectation(description: \"request should succeed and return ip\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(contentType: [\"application/json\"])\n            .validate(contentType: [\"application/json; charset=utf-8\"])\n            .validate(contentType: [\"application/json; q=0.8; charset=utf-8\"])\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(requestError)\n    }\n\n    func testThatValidationForRequestWithAcceptableWildcardContentTypeResponseSucceeds() {\n        // Given\n        let urlString = \"https://httpbin.org/ip\"\n\n        let expectation1 = self.expectation(description: \"request should succeed and return ip\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(contentType: [\"*/*\"])\n            .validate(contentType: [\"application/*\"])\n            .validate(contentType: [\"*/json\"])\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(requestError)\n    }\n\n    func testThatValidationForRequestWithUnacceptableContentTypeResponseFails() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n\n        let expectation1 = self.expectation(description: \"request should succeed and return html\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(contentType: [\"application/octet-stream\"])\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(requestError)\n\n        for error in [requestError] {\n            if let error = error as? CLDNError {\n                XCTAssertTrue(error.isUnacceptableContentType)\n                XCTAssertEqual(error.responseContentType, \"text/html\")\n                XCTAssertEqual(error.acceptableContentTypes?.first, \"application/octet-stream\")\n            } else {\n                XCTFail(\"error should not be nil\")\n            }\n        }\n    }\n\n    func testThatValidationForRequestWithNoAcceptableContentTypeResponseFails() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n\n        let expectation1 = self.expectation(description: \"request should succeed and return html\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(contentType: [])\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(requestError)\n\n        for error in [requestError] {\n            if let error = error as? CLDNError {\n                XCTAssertTrue(error.isUnacceptableContentType)\n                XCTAssertEqual(error.responseContentType, \"text/html\")\n                XCTAssertTrue(error.acceptableContentTypes?.isEmpty ?? false)\n            } else {\n                XCTFail(\"error should not be nil\")\n            }\n        }\n    }\n\n    func skipped_testThatValidationForRequestWithNoAcceptableContentTypeResponseSucceedsWhenNoDataIsReturned() {\n        // Given\n        let urlString = \"https://mockbin.org/\"\n\n        let expectation1 = self.expectation(description: \"request should succeed and return no data\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(contentType: [])\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(requestError)\n    }\n\n    func testThatValidationForRequestWithAcceptableWildcardContentTypeResponseSucceedsWhenResponseIsNil() {\n        // Given\n        class MockManager: CLDNSessionManager {\n            override func request(_ urlRequest: CLDNURLRequestConvertible) -> CLDNDataRequest {\n                do {\n                    let originalRequest = try urlRequest.CLDN_AsURLRequest()\n                    let originalTask = CLDNDataRequest.Requestable(urlRequest: originalRequest)\n\n                    let task = try originalTask.CLDN_Task(session: session, adapter: adapter, queue: queue)\n                    let request = MockDataRequest(session: session, requestTask: .data(originalTask, task))\n\n                    delegate[task] = request\n\n                    if startRequestsImmediately { request.resume() }\n\n                    return request\n                } catch {\n                    let request = CLDNDataRequest(session: session, requestTask: .data(nil, nil), error: error)\n                    if startRequestsImmediately { request.resume() }\n                    return request\n                }\n            }\n        }\n\n        class MockDataRequest: CLDNDataRequest {\n            override var response: HTTPURLResponse? {\n                return MockHTTPURLResponse(\n                    url: request!.url!,\n                    statusCode: 204,\n                    httpVersion: \"HTTP/1.1\",\n                    headerFields: nil\n                )\n            }\n        }\n\n        class MockHTTPURLResponse: HTTPURLResponse {\n            override var mimeType: String? { return nil }\n        }\n\n        let manager: CLDNSessionManager = {\n            let configuration: URLSessionConfiguration = {\n                let configuration = URLSessionConfiguration.ephemeral\n                configuration.httpAdditionalHeaders = CLDNSessionManager.defaultHTTPHeaders\n\n                return configuration\n            }()\n\n            return MockManager(configuration: configuration)\n        }()\n\n        let urlString = \"https://httpbin.org/delete\"\n\n        let expectation1 = self.expectation(description: \"request should be stubbed and return 204 status code\")\n\n        var requestResponse: CLDNDefaultDataResponse?\n\n        // When\n        manager.request(urlString, method: .delete)\n            .validate(contentType: [\"*/*\"])\n            .response { resp in\n                requestResponse = resp\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(requestResponse?.response)\n        XCTAssertNotNil(requestResponse?.data)\n        XCTAssertNil(requestResponse?.error)\n\n        XCTAssertEqual(requestResponse?.response?.statusCode, 204)\n        XCTAssertNil(requestResponse?.response?.mimeType)\n    }\n}\n\n// MARK: -\n\nclass MultipleValidationTestCase: BaseTestCase {\n    func testThatValidationForRequestWithAcceptableStatusCodeAndContentTypeResponseSucceeds() {\n        // Given\n        let urlString = \"https://httpbin.org/ip\"\n\n        let expectation1 = self.expectation(description: \"request should succeed and return ip\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(statusCode: 200..<300)\n            .validate(contentType: [\"application/json\"])\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(requestError)\n    }\n\n    func testThatValidationForRequestWithUnacceptableStatusCodeAndContentTypeResponseFailsWithStatusCodeError() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n\n        let expectation1 = self.expectation(description: \"request should succeed and return status code 200\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(statusCode: 400..<600)\n            .validate(contentType: [\"application/octet-stream\"])\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(requestError)\n\n        for error in [requestError] {\n            if let error = error as? CLDNError {\n                XCTAssertTrue(error.isUnacceptableStatusCode)\n                XCTAssertEqual(error.responseCode, 200)\n            } else {\n                XCTFail(\"error should not be nil\")\n            }\n        }\n    }\n\n    func testThatValidationForRequestWithUnacceptableStatusCodeAndContentTypeResponseFailsWithContentTypeError() {\n        // Given\n        let urlString = \"https://httpbin.org/\"\n\n        let expectation1 = self.expectation(description: \"request should succeed and return html\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(contentType: [\"application/octet-stream\"])\n            .validate(statusCode: 400..<600)\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(requestError)\n\n        for error in [requestError] {\n            if let error = error as? CLDNError {\n                XCTAssertTrue(error.isUnacceptableContentType)\n                XCTAssertEqual(error.responseContentType, \"text/html\")\n                XCTAssertEqual(error.acceptableContentTypes?.first, \"application/octet-stream\")\n            } else {\n                XCTFail(\"error should not be nil\")\n            }\n        }\n    }\n}\n\n// MARK: -\n\nclass AutomaticValidationTestCase: BaseTestCase {\n    func testThatValidationForRequestWithAcceptableStatusCodeAndContentTypeResponseSucceeds() {\n\n        // Given\n        let url = URL(string: \"https://httpbin.org/ip\")!\n        var urlRequest = URLRequest(url: url)\n        urlRequest.setValue(\"application/json\", forHTTPHeaderField: \"Accept\")\n\n        let expectation1 = self.expectation(description: \"request should succeed and return ip\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlRequest).validate().response { resp in\n            requestError = resp.error\n            expectation1.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(requestError)\n    }\n\n    func testThatValidationForRequestWithUnacceptableStatusCodeResponseFails() {\n        // Given\n        let urlString = \"https://httpbin.org/status/404\"\n\n        let expectation1 = self.expectation(description: \"request should return 404 status code\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate()\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(requestError)\n\n        for error in [requestError] {\n            if let error = error as? CLDNError, let statusCode = error.responseCode {\n                XCTAssertTrue(error.isUnacceptableStatusCode)\n                XCTAssertEqual(statusCode, 404)\n            } else {\n                XCTFail(\"error should not be nil\")\n            }\n        }\n    }\n\n    func testThatValidationForRequestWithAcceptableWildcardContentTypeResponseSucceeds() {\n        // Given\n        let url = URL(string: \"https://httpbin.org/ip\")!\n        var urlRequest = URLRequest(url: url)\n        urlRequest.setValue(\"application/*\", forHTTPHeaderField: \"Accept\")\n\n        let expectation1 = self.expectation(description: \"request should succeed and return ip\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlRequest).validate().response { resp in\n            requestError = resp.error\n            expectation1.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(requestError)\n    }\n\n    func testThatValidationForRequestWithAcceptableComplexContentTypeResponseSucceeds() {\n        // Given\n        let url = URL(string: \"https://httpbin.org/\")!\n        var urlRequest = URLRequest(url: url)\n\n        let headerValue = \"text/xml, application/xml, application/xhtml+xml, text/html;q=0.9, text/plain;q=0.8,*/*;q=0.5\"\n        urlRequest.setValue(headerValue, forHTTPHeaderField: \"Accept\")\n\n        let expectation1 = self.expectation(description: \"request should succeed and return xml\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlRequest).validate().response { resp in\n            requestError = resp.error\n            expectation1.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(requestError)\n    }\n\n    func testThatValidationForRequestWithUnacceptableContentTypeResponseFails() {\n        // Given\n        let url = URL(string: \"https://httpbin.org/\")!\n        var urlRequest = URLRequest(url: url)\n        urlRequest.setValue(\"application/json\", forHTTPHeaderField: \"Accept\")\n\n        let expectation1 = self.expectation(description: \"request should succeed and return html\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlRequest).validate().response { resp in\n            requestError = resp.error\n            expectation1.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(requestError)\n\n        for error in [requestError] {\n            if let error = error as? CLDNError {\n                XCTAssertTrue(error.isUnacceptableContentType)\n                XCTAssertEqual(error.responseContentType, \"text/html\")\n                XCTAssertEqual(error.acceptableContentTypes?.first, \"application/json\")\n            } else {\n                XCTFail(\"error should not be nil\")\n            }\n        }\n    }\n}\n\n// MARK: -\n\nprivate enum ValidationError: Error {\n    case missingData, missingFile, fileReadFailed\n}\n\nextension CLDNDataRequest {\n    func validateDataExists() -> Self {\n        return validate { request, response, data in\n            guard data != nil else { return .failure(ValidationError.missingData) }\n            return .success\n        }\n    }\n\n    func validate(with error: Error) -> Self {\n        return validate { _, _, _ in .failure(error) }\n    }\n}\n\n// MARK: -\n\nclass CustomValidationTestCase: BaseTestCase {\n    func testThatCustomValidationClosureHasAccessToServerResponseData() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n\n        let expectation1 = self.expectation(description: \"request should return 200 status code\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate { request, response, data in\n                guard data != nil else { return .failure(ValidationError.missingData) }\n                return .success\n            }\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(requestError)\n    }\n\n    func testThatCustomValidationCanThrowCustomError() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n\n        let expectation1 = self.expectation(description: \"request should return 200 status code\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate { _, _, _ in .failure(ValidationError.missingData) }\n            .validate { _, _, _ in .failure(ValidationError.missingFile) } // should be ignored\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertEqual(requestError as? ValidationError, ValidationError.missingData)\n    }\n\n    func testThatValidationExtensionHasAccessToServerResponseData() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n\n        let expectation1 = self.expectation(description: \"request should return 200 status code\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validateDataExists()\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n        }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(requestError)\n    }\n\n    func testThatValidationExtensionCanThrowCustomError() {\n        // Given\n        let urlString = \"https://httpbin.org/get\"\n\n        let expectation1 = self.expectation(description: \"request should return 200 status code\")\n\n        var requestError: Error?\n\n        // When\n        CLDNSessionManager.default.request(urlString)\n            .validate(with: ValidationError.missingData)\n            .validate(with: ValidationError.missingFile) // should be ignored\n            .response { resp in\n                requestError = resp.error\n                expectation1.fulfill()\n            }\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertEqual(requestError as? ValidationError, ValidationError.missingData)\n    }\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/ObjcBaseTestCase.h",
    "content": "//\n//  ObjcBaseTestCase.h\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"Cloudinary_Tests-Swift.h\"\n\n\n@interface ObjcBaseTestCase: XCTestCase\n\n@property (nonatomic, assign) NSTimeInterval timeout;\n\n- (BOOL)shouldSkipTest;\n\n@end\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/ObjcBaseTestCase.m",
    "content": "//\n//  ObjcBaseTestCase.m\n//  Cloudinary_Tests\n//\n//  Created by Oz Deutsch on 24/09/2020.\n//  Copyright © 2020 CocoaPods. All rights reserved.\n//\n\n#import \"ObjcBaseTestCase.h\"\n\n@implementation ObjcBaseTestCase\n\n- (BOOL)setUpWithError:(NSError *__autoreleasing  _Nullable *)error {\n    \n   XCTSkipIf([self shouldSkipTest], \"test skipped\");\n    \n   return [super setUpWithError:error];\n}\n\n/**\n override this method to skip tests when needed\n*/\n- (BOOL)shouldSkipTest {\n    return false;\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Resources/Responses/JSON/empty_data.json",
    "content": ""
  },
  {
    "path": "Example/Tests/BaseNetwork/Resources/Responses/JSON/invalid_data.json",
    "content": "this is not going\n\"to\" be happy json\ndata at all\n{\n    \"10\": whoops\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Resources/Responses/JSON/valid_data.json",
    "content": "{\n    \"team\": \"royals\",\n    \"score\": 23\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Resources/Responses/Property List/empty.data",
    "content": ""
  },
  {
    "path": "Example/Tests/BaseNetwork/Resources/Responses/Property List/invalid.data",
    "content": "this is not going\n\"to\" be happy json\ndata at all\n{\n    \"10\": whoops\n}\n"
  },
  {
    "path": "Example/Tests/BaseNetwork/Resources/Responses/Property List/valid.data",
    "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>4.0.0-beta.2</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": "Example/Tests/BaseNetwork/Resources/Responses/String/empty_string.txt",
    "content": ""
  },
  {
    "path": "Example/Tests/BaseNetwork/Resources/Responses/String/utf8_string.txt",
    "content": "random data"
  },
  {
    "path": "Example/Tests/ConfigurationTests/CLDAnalyticsTests.swift",
    "content": "//\n//  CLDAnalyticsTests.swift\n//  Cloudinary_Tests\n//\n//  Created by Adi Mizrahi on 26/07/2022.\n//  Copyright © 2022 CocoaPods. All rights reserved.\n//\n\nimport Foundation\nimport Cloudinary\nimport XCTest\nclass CLDAnalyticsTests: BaseTestCase {\n\n    func test_analyicsString() {\n        var analyticsString = CLDAnalytics().generateAnalyticsSignature(sdkVersion: \"1.24.0\",techVersion: \"12.0\", osType: \"B\", osVersion: \"12.0\")\n        XCTAssertEqual(analyticsString, \"DAEAlhAMBMA0\")\n\n        analyticsString = CLDAnalytics().generateAnalyticsSignature(sdkVersion: \"1.24.0-beta.6\",techVersion: \"12.0\", osType: \"B\", osVersion: \"12.0\")\n        XCTAssertEqual(analyticsString, \"DAEAlhAMBMA0\")\n\n        analyticsString = CLDAnalytics().generateAnalyticsSignature(sdkVersion: \"1.24.0\",techVersion: \"16.3\", osType: \"B\", osVersion: \"16.3\")\n        XCTAssertEqual(analyticsString, \"DAEAlhE8BQD0\")\n\n        analyticsString = CLDAnalytics().generateAnalyticsSignature(sdkVersion: \"1.24.0\",techVersion: \"17.1\", osType: \"B\", osVersion: \"17.1\")\n        XCTAssertEqual(analyticsString, \"DAEAlhB1BRB0\")\n    }\n\n    func test_errorAnalytics() {\n        var analyticsString = CLDAnalytics().generateAnalyticsSignature(sdkVersion: \"1.24.0\",techVersion: \"0\")\n        XCTAssertEqual(analyticsString, \"E\")\n\n        analyticsString = CLDAnalytics().generateAnalyticsSignature(sdkVersion: \"0\",techVersion: \"12.0\")\n        XCTAssertEqual(analyticsString, \"E\")\n\n        analyticsString = CLDAnalytics().generateAnalyticsSignature(sdkVersion: \"\",techVersion: \"12.0\")\n        XCTAssertEqual(analyticsString, \"E\")\n\n        analyticsString = CLDAnalytics().generateAnalyticsSignature(sdkVersion: \"1.24.0\",techVersion: \"\")\n        XCTAssertEqual(analyticsString, \"E\")\n\n        analyticsString = CLDAnalytics().generateAnalyticsSignature(sdkVersion: \"43.21.26\",techVersion: \"5.0\", osVersion: \"17.1\")\n        XCTAssertEqual(analyticsString, \"DAE;;;AFBRB0\")\n    }\n\n    func test_analyticsInitialized() {\n        let analytics = CLDAnalytics(sdkVersion: \"1.24.0\",techVersion: \"12.0\", osType: \"B\", osVersion: \"12.0\")\n        XCTAssertEqual(analytics.generateAnalyticsSignature(), \"DAEAlhAMBMA0\")\n\n        analytics.setSDKVersion(version: \"1.25.0\")\n        XCTAssertEqual(analytics.generateAnalyticsSignature(), \"DAEAnFAMBMA0\")\n\n        analytics.setTechVersion(version: \"13.0\")\n        XCTAssertEqual(analytics.generateAnalyticsSignature(), \"DAEAnFANBMA0\")\n\n        analytics.setOsVersion(version: \"17.1\")\n        XCTAssertEqual(analytics.generateAnalyticsSignature(), \"DAEAnFANBRB0\")\n    }\n\n    func test_analyticsFeatureFlag() {\n        let analytics = CLDAnalytics(sdkVersion: \"1.24.0\",techVersion: \"12.0\", osType: \"B\", osVersion: \"12.0\", featureFlag: \"E\")\n        XCTAssertEqual(analytics.generateAnalyticsSignature(), \"DAEAlhAMBMAE\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/ConfigurationTests/CLDConfigurationTests.m",
    "content": "//\n//  ObjcCLDConfigurationTests.m\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"ObjcBaseTestCase.h\"\n\n@interface ObjcCLDConfigurationTests : ObjcBaseTestCase\n@property (nonatomic, strong, nullable) CLDConfiguration* sut;\n@end\n\n@implementation ObjcCLDConfigurationTests\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n}\n\n- (void)tearDown {\n    [super tearDown];\n    self.sut = nil;\n}\n\n// MARK: - timeout\n- (void)test_initTimeout_setNSNumber_shouldStoreValue {\n    \n    // Given\n    NSNumber* input = [[NSNumber alloc] initWithInt:10000];\n    \n    NSNumber* expectedResult = [[NSNumber alloc] initWithInt:10000];\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithCloudName:@\"\"\n                                                    apiKey:nil\n                                                 apiSecret:nil\n                                                privateCdn:NO\n                                                    secure:NO\n                                              cdnSubdomain:NO\n                                        secureCdnSubdomain:NO\n                                          longUrlSignature:NO\n                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                          signatureVersion:2\n                                        secureDistribution:nil\n                                                     cname:nil\n                                              uploadPrefix:nil\n                                                   timeout:input\n                                                 analytics:NO];\n    \n    // Then\n    XCTAssertEqualObjects(self.sut.timeout, expectedResult, \"Init with timeout = number, should be stored in property\");\n}\n\n- (void)test_initTimeout_nil_shouldStoreFalseValue {\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithCloudName:@\"\"\n                                                    apiKey:nil\n                                                 apiSecret:nil\n                                                privateCdn:NO\n                                                    secure:NO\n                                              cdnSubdomain:NO\n                                        secureCdnSubdomain:NO\n                                          longUrlSignature:NO\n                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                          signatureVersion:2\n                                        secureDistribution:nil\n                                                     cname:nil\n                                              uploadPrefix:nil\n                                                   timeout:nil\n                                                 analytics:NO];\n    \n    // Then\n    XCTAssertNil(self.sut.timeout, \"Init with timeout = nil, should not be stored in property\");\n}\n- (void)test_initTimeout_optionsString_shouldStoreValue {\n    \n    // Given\n    NSString* keyCloudName   = @\"cloud_name\";\n    NSString* inputCloudName = @\"foo\";\n    NSString* keyTimeout     = @\"timeout\";\n    NSString* inputTimeout   = @\"10000\";\n    \n    NSNumber* expectedResult = [[NSNumber alloc] initWithInt:10000];\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithOptions:@{keyCloudName: inputCloudName, keyTimeout: inputTimeout}];\n    \n    // Then\n    XCTAssertEqualObjects(self.sut.timeout, expectedResult, \"Init with timeout = number, should be stored in property\");\n}\n- (void)test_initTimeout_optionsNSNumber_shouldStoreValue {\n    \n    // Given\n    NSString* keyCloudName   = @\"cloud_name\";\n    NSString* inputCloudName = @\"foo\";\n    NSString* keyTimeout     = @\"timeout\";\n    NSNumber* inputTimeout   = [[NSNumber alloc] initWithInt:10000];\n    \n    NSNumber* expectedResult = [[NSNumber alloc] initWithInt:10000];\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithOptions:@{keyCloudName: inputCloudName, keyTimeout: inputTimeout}];\n    \n    // Then\n    XCTAssertEqualObjects(self.sut.timeout, expectedResult, \"Init with timeout = number, should be stored in property\");\n}\n- (void)test_initTimeout_cloudinaryUrl_shouldStoreValue {\n    \n    // Given\n    NSString* longUrlSignatureQuery = @\"?timeout=10000\";\n    NSString* testedUrl             = @\"cloudinary://123456789012345:ALKJdjklLJAjhkKJ45hBK92baj3@test\";\n    NSString* fullUrl               = [NSString stringWithFormat:@\"%@%@\",testedUrl,longUrlSignatureQuery];\n    \n    NSNumber* expectedResult = [[NSNumber alloc] initWithInt:10000];\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithCloudinaryUrl:fullUrl];\n    \n    // Then\n    XCTAssertEqualObjects(self.sut.timeout, expectedResult, \"Init with cloudinaryUrl with valid timeout, should be stored in property\");\n}\n\n// MARK: - long url signature\n- (void)test_initLongUrlSignature_true_shouldStoreValue {\n        \n    // Given\n    BOOL input = YES;\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithCloudName:@\"\"\n                                                    apiKey:nil\n                                                 apiSecret:nil\n                                                privateCdn:NO\n                                                    secure:NO\n                                              cdnSubdomain:NO\n                                        secureCdnSubdomain:NO\n                                          longUrlSignature:input\n                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                          signatureVersion:2\n                                        secureDistribution:nil\n                                                     cname:nil\n                                              uploadPrefix:nil\n                                                   timeout:nil\n                                                 analytics:NO];\n    \n    // Then\n    XCTAssertTrue(self.sut.longUrlSignature, \"Init with longUrlSignature = true, should be stored in property\");\n}\n- (void)test_initLongUrlSignature_default_shouldStoreFalseValue {\n\n    // When\n    self.sut = [[CLDConfiguration alloc] initWithCloudName:@\"\"\n                                                    apiKey:nil\n                                                 apiSecret:nil\n                                                privateCdn:NO\n                                                    secure:NO\n                                              cdnSubdomain:NO\n                                        secureCdnSubdomain:NO\n                                          longUrlSignature:NO\n                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                          signatureVersion:2\n                                        secureDistribution:nil\n                                                     cname:nil\n                                              uploadPrefix:nil\n                                                   timeout:nil\n                                                 analytics:NO];\n    \n    // Then\n    XCTAssertFalse(self.sut.longUrlSignature, \"Init without longUrlSignature should store the default false value\");\n}\n- (void)test_initLongUrlSignature_optionsString_shouldStoreValue {\n        \n    // Given\n    NSString* keyCloudName          = @\"cloud_name\";\n    NSString* inputCloudName        = @\"foo\";\n    NSString* keyLongUrlSignature   = @\"long_url_signature\";\n    NSString* inputLongUrlSignature = @\"true\";\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithOptions:@{keyCloudName: inputCloudName, keyLongUrlSignature: inputLongUrlSignature}];\n    \n    // Then\n    XCTAssertTrue(self.sut.longUrlSignature, \"Init with options with longUrlSignature = true, should be stored in property\");\n}\n- (void)test_initLongUrlSignature_optionsBool_shouldStoreValue {\n        \n    // Given\n    NSString* keyCloudName          = @\"cloud_name\";\n    NSString* inputCloudName        = @\"foo\";\n    NSString* keyLongUrlSignature   = @\"long_url_signature\";\n    NSNumber* inputLongUrlSignature = @YES;\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithOptions:@{keyCloudName: inputCloudName, keyLongUrlSignature: inputLongUrlSignature}];\n    \n    // Then\n    XCTAssertTrue(self.sut.longUrlSignature, \"Init with options with longUrlSignature = true, should be stored in property\");\n}\n- (void)test_initLongUrlSignature_cloudinaryUrl_shouldStoreValue {\n        \n    // Given\n    NSString* longUrlSignatureQuery = @\"?long_url_signature=true\";\n    NSString* testedUrl             = @\"cloudinary://123456789012345:ALKJdjklLJAjhkKJ45hBK92baj3@test\";\n    NSString* fullUrl               = [NSString stringWithFormat:@\"%@%@\",testedUrl,longUrlSignatureQuery];\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithCloudinaryUrl:fullUrl];\n    \n    // Then\n    XCTAssertTrue(self.sut.longUrlSignature, \"Init with cloudinaryUrl with valid longUrlSignature = true, should be stored in property\");\n}\n\n// MARK: - signature algorithm\n- (void)test_initSignatureAlgorithm_setSha256_shouldStoreValue {\n        \n    // Given\n    BOOL input = SignatureAlgorithmSha256;\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithCloudName:@\"\"\n                                                    apiKey:nil\n                                                 apiSecret:nil\n                                                privateCdn:NO\n                                                    secure:NO\n                                              cdnSubdomain:NO\n                                        secureCdnSubdomain:NO\n                                          longUrlSignature:NO\n                                        signatureAlgorithm:input\n                                          signatureVersion:2\n                                        secureDistribution:nil\n                                                     cname:nil\n                                              uploadPrefix:nil\n                                                   timeout:nil\n                                                 analytics:NO];\n    \n    // Then\n    XCTAssertEqual(self.sut.signatureAlgorithm, SignatureAlgorithmSha256, \"Init with signatureAlgorithm should store that value in property\");\n}\n- (void)test_initSignatureAlgorithm_default_shouldStoreDefaultValue {\n\n    // When\n    self.sut = [[CLDConfiguration alloc] initWithCloudName:@\"\"\n                                                    apiKey:nil\n                                                 apiSecret:nil\n                                                privateCdn:NO\n                                                    secure:NO\n                                              cdnSubdomain:NO\n                                        secureCdnSubdomain:NO\n                                          longUrlSignature:NO\n                                        signatureAlgorithm:0\n                                          signatureVersion:2\n                                        secureDistribution:nil\n                                                     cname:nil\n                                              uploadPrefix:nil\n                                                   timeout:nil\n                                                 analytics:NO];\n    \n    // Then\n    XCTAssertEqual(self.sut.signatureAlgorithm, SignatureAlgorithmSha1, \"Init without signatureAlgorithm should store the default .sha1 value\");\n}\n- (void)test_initSignatureAlgorithm_optionsSha256_shouldStoreValue {\n        \n    // Given\n    NSString* keyCloudName            = @\"cloud_name\";\n    NSString* inputCloudName          = @\"foo\";\n    NSString* keySignatureAlgorithm   = @\"signature_algorithm\";\n    NSString* inputSignatureAlgorithm = @\"sha256\";\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithOptions:@{keyCloudName: inputCloudName, keySignatureAlgorithm: inputSignatureAlgorithm}];\n    \n    // Then\n    XCTAssertEqual(self.sut.signatureAlgorithm, SignatureAlgorithmSha256, \"Init with options with signatureAlgorithm should store that value\");\n}\n- (void)test_initSignatureAlgorithm_optionsSha1_shouldStoreValue {\n        \n    // Given\n    NSString* keyCloudName            = @\"cloud_name\";\n    NSString* inputCloudName          = @\"foo\";\n    NSString* keySignatureAlgorithm   = @\"signature_algorithm\";\n    NSString* inputSignatureAlgorithm = @\"sha1\";\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithOptions:@{keyCloudName: inputCloudName, keySignatureAlgorithm: inputSignatureAlgorithm}];\n    \n    // Then\n    XCTAssertEqual(self.sut.signatureAlgorithm, SignatureAlgorithmSha1, \"Init with options with signatureAlgorithm should store that value\");\n}\n- (void)test_initSignatureAlgorithm_optionsInvalidString_shouldStoreValue {\n        \n    // Given\n    NSString* keyCloudName            = @\"cloud_name\";\n    NSString* inputCloudName          = @\"foo\";\n    NSString* keySignatureAlgorithm   = @\"signature_algorithm\";\n    NSString* inputSignatureAlgorithm = @\"notSha\";\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithOptions:@{keyCloudName: inputCloudName, keySignatureAlgorithm: inputSignatureAlgorithm}];\n    \n    // Then\n    XCTAssertEqual(self.sut.signatureAlgorithm, SignatureAlgorithmSha1, \"Init with options with invalid signatureAlgorithm should store the defualt .sha1 value\");\n}\n- (void)test_initSignatureAlgorithm_cloudinaryUrl_shouldStoreValue {\n        \n    // Given\n    NSString* signatureAlgorithmQuery = @\"?signature_algorithm=sha256\";\n    NSString* testedUrl               = @\"cloudinary://123456789012345:ALKJdjklLJAjhkKJ45hBK92baj3@test\";\n    NSString* fullUrl                 = [NSString stringWithFormat:@\"%@%@\",testedUrl,signatureAlgorithmQuery];\n    \n    // When\n    self.sut = [[CLDConfiguration alloc] initWithCloudinaryUrl:fullUrl];\n    \n    // Then\n    XCTAssertEqual(self.sut.signatureAlgorithm, SignatureAlgorithmSha256, \"Init with cloudinaryUrl with valid signatureAlgorithm should store that value\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/ConfigurationTests/CLDConfigurationTests.swift",
    "content": "//\n//  CLDConfigurationTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass CLDConfigurationTests: BaseTestCase {\n    \n    var sut : CLDConfiguration!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = CLDConfiguration(cloudName: \"\")\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - long url signature\n    func test_initLongUrlSignature_true_shouldStoreValue() {\n        \n        // Given\n        let input = true\n        \n        // When\n        sut = CLDConfiguration(cloudName: \"\", longUrlSignature: input)\n        \n        // Then\n        XCTAssertTrue(sut.longUrlSignature, \"Init with longUrlSignature = true, should be stored in property\")\n    }\n    func test_initLongUrlSignature_default_shouldStoreFalseValue() {\n        \n        // When\n        sut = CLDConfiguration(cloudName: \"\")\n        \n        // Then\n        XCTAssertFalse(sut.longUrlSignature, \"Init without longUrlSignature should store the default false value\")\n    }\n    func test_initLongUrlSignature_optionsString_shouldStoreValue() {\n        \n        // Given\n        let keyCloudName          = CLDConfiguration.ConfigParam.CloudName.rawValue\n        let inputCloudName        = \"foo\" as AnyObject\n        let keyLongUrlSignature   = CLDConfiguration.ConfigParam.LongUrlSignature.rawValue\n        let inputLongUrlSignature = \"true\" as AnyObject\n        \n        // When\n        sut = CLDConfiguration(options: [keyCloudName: inputCloudName, keyLongUrlSignature: inputLongUrlSignature])\n        \n        // Then\n        XCTAssertTrue(sut.longUrlSignature, \"Init with options with longUrlSignature = true, should be stored in property\")\n    }\n    func test_initLongUrlSignature_optionsBool_shouldStoreValue() {\n        \n        // Given\n        let keyCloudName          = CLDConfiguration.ConfigParam.CloudName.rawValue\n        let inputCloudName        = \"foo\" as AnyObject\n        let keyLongUrlSignature   = CLDConfiguration.ConfigParam.LongUrlSignature.rawValue\n        let inputLongUrlSignature = true as AnyObject\n        \n        // When\n        sut = CLDConfiguration(options: [keyCloudName: inputCloudName, keyLongUrlSignature: inputLongUrlSignature])\n        \n        // Then\n        XCTAssertTrue(sut.longUrlSignature, \"Init with options with longUrlSignature = true, should be stored in property\")\n    }\n    func test_initLongUrlSignature_cloudinaryUrl_shouldStoreValue() {\n        \n        // Given\n        let longUrlSignatureQuery = (\"?\\(CLDConfiguration.ConfigParam.LongUrlSignature.description)=true\")\n        let testedUrl             = \"cloudinary://123456789012345:ALKJdjklLJAjhkKJ45hBK92baj3@test\"\n        let fullUrl               = testedUrl + longUrlSignatureQuery\n        \n        // When\n        sut = CLDConfiguration(cloudinaryUrl: fullUrl)\n        \n        // Then\n        XCTAssertTrue(sut.longUrlSignature, \"Init with cloudinaryUrl with valid longUrlSignature = true, should be stored in property\")\n    }\n    \n    // MARK: - signature algorithm\n    func test_initSignatureAlgorithm_setSha256_shouldStoreValue() {\n        \n        // Given\n        let input = CLDConfiguration.SignatureAlgorithm.sha256\n        \n        // When\n        sut = CLDConfiguration(cloudName: String(), signatureAlgorithm: input)\n        \n        // Then\n        XCTAssertEqual(sut.signatureAlgorithm, .sha256, \"Init with signatureAlgorithm should store that value\")\n    }\n    func test_initSignatureAlgorithm_default_shouldStoreDefaultValue() {\n       \n        // When\n        sut = CLDConfiguration(cloudName: String())\n        \n        // Then\n        XCTAssertEqual(sut.signatureAlgorithm, .sha1, \"Init without signatureAlgorithm should store the default .sha1 value\")\n    }\n    func test_initSignatureAlgorithm_optionsString_shouldStoreValue() {\n        \n        // Given\n        let keyCloudName            = CLDConfiguration.ConfigParam.CloudName.rawValue\n        let inputCloudName          = \"foo\" as AnyObject\n        let keySignatureAlgorithm   = CLDConfiguration.ConfigParam.SignatureAlgorithm.rawValue\n        let inputSignatureAlgorithm = \"sha256\" as AnyObject\n        \n        // When\n        sut = CLDConfiguration(options: [keyCloudName: inputCloudName, keySignatureAlgorithm: inputSignatureAlgorithm])\n        \n        // Then\n        XCTAssertEqual(sut.signatureAlgorithm, .sha256, \"Init with options with signatureAlgorithm should store that value\")\n    }\n    func test_initSignatureAlgorithm_optionsEnum_shouldStoreValue() {\n        \n        // Given\n        let keyCloudName            = CLDConfiguration.ConfigParam.CloudName.rawValue\n        let inputCloudName          = \"foo\" as AnyObject\n        let keySignatureAlgorithm   = CLDConfiguration.ConfigParam.SignatureAlgorithm.rawValue\n        let inputSignatureAlgorithm = CLDConfiguration.SignatureAlgorithm.sha256 as AnyObject\n        \n        // When\n        sut = CLDConfiguration(options: [keyCloudName: inputCloudName, keySignatureAlgorithm: inputSignatureAlgorithm])\n        \n        // Then\n        XCTAssertEqual(sut.signatureAlgorithm, .sha256, \"Init with options with signatureAlgorithm should store that value\")\n    }\n    func test_initSignatureAlgorithm_optionsInvalidString_shouldStoreValue() {\n        \n        // Given\n        let keyCloudName            = CLDConfiguration.ConfigParam.CloudName.rawValue\n        let inputCloudName          = \"foo\" as AnyObject\n        let keySignatureAlgorithm   = CLDConfiguration.ConfigParam.SignatureAlgorithm.rawValue\n        let inputSignatureAlgorithm = \"notSha\" as AnyObject\n        \n        // When\n        sut = CLDConfiguration(options: [keyCloudName: inputCloudName, keySignatureAlgorithm: inputSignatureAlgorithm])\n        \n        // Then\n        XCTAssertEqual(sut.signatureAlgorithm, .sha1, \"Init with options with invalid signatureAlgorithm should store the default .sha1 value\")\n    }\n    func test_initSignatureAlgorithm_cloudinaryUrl_shouldStoreValue() {\n        \n        // Given\n        let signatureAlgorithmQuery = (\"?\\(CLDConfiguration.ConfigParam.SignatureAlgorithm.description)=sha256\")\n        let testedUrl               = \"cloudinary://123456789012345:ALKJdjklLJAjhkKJ45hBK92baj3@test\"\n        let fullUrl                 = testedUrl + signatureAlgorithmQuery\n        \n        // When\n        sut = CLDConfiguration(cloudinaryUrl: fullUrl)\n\n        // Then\n        XCTAssertEqual(sut.signatureAlgorithm, .sha256,\"Init with cloudinaryUrl with valid signatureAlgorithm should store that value\")\n    }\n    \n    // MARK: - timeout\n    func test_initTimeout_setNSNumber_shouldStoreValue() {\n        \n        // Given\n        let input = NSNumber(integerLiteral: 10000)\n        \n        let expectedResult = NSNumber(integerLiteral: 10000)\n        \n        // When\n        sut = CLDConfiguration(cloudName: \"\", timeout: input)\n        \n        // Then\n        XCTAssertEqual(sut.timeout, expectedResult, \"Init with timeout = number, should be stored in property\")\n    }\n    func test_initTimeout_nilIsDefault_shouldStoreFalseValue() {\n        // When\n        sut = CLDConfiguration(cloudName: \"\")\n        \n        // Then\n        \n        XCTAssertFalse(sut.longUrlSignature, \"Init without longUrlSignature should store the default false value\")\n    }\n    \n    func test_initTimeout_optionsString_shouldStoreValue() {\n        \n        // Given\n        let keyCloudName   = CLDConfiguration.ConfigParam.CloudName.rawValue\n        let inputCloudName = \"foo\" as AnyObject\n        let keyTimeout     = CLDConfiguration.ConfigParam.Timeout.rawValue\n        let inputTimeout   = \"10000\" as AnyObject\n        \n        let expectedResult = NSNumber(integerLiteral: 10000)\n        \n        // When\n        sut = CLDConfiguration(options: [keyCloudName: inputCloudName, keyTimeout: inputTimeout])\n        \n        // Then\n        XCTAssertEqual(sut.timeout, expectedResult, \"Init with timeout = number, should be stored in property\")\n    }\n    func test_initTimeout_optionsInt_shouldStoreValue() {\n        \n        // Given\n        let keyCloudName   = CLDConfiguration.ConfigParam.CloudName.rawValue\n        let inputCloudName = \"foo\" as AnyObject\n        let keyTimeout     = CLDConfiguration.ConfigParam.Timeout.rawValue\n        let inputTimeout   = 10000 as AnyObject\n        \n        let expectedResult = NSNumber(integerLiteral: 10000)\n        \n        // When\n        sut = CLDConfiguration(options: [keyCloudName: inputCloudName, keyTimeout: inputTimeout])\n        \n        // Then\n        XCTAssertEqual(sut.timeout, expectedResult, \"Init with timeout = number, should be stored in property\")\n    }\n    func test_initTimeout_cloudinaryUrl_shouldStoreValue() {\n        \n        // Given\n        let timeoutQuery = (\"?\\(CLDConfiguration.ConfigParam.Timeout.description)=10000\")\n        let testedUrl    = \"cloudinary://123456789012345:ALKJdjklLJAjhkKJ45hBK92baj3@test\"\n        let fullUrl      = testedUrl + timeoutQuery\n        \n        let expectedResult = NSNumber(integerLiteral: 10000)\n        \n        // When\n        sut = CLDConfiguration(cloudinaryUrl: fullUrl)\n        // Then\n        XCTAssertEqual(sut.timeout, expectedResult, \"Init with cloudinaryUrl with valid timeout, should be stored in property\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/CryptoUtilsTests/CryptoUtilsTests.m",
    "content": "//\n//  CryptoUtilsTests.m\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import <Cloudinary_Tests-Swift.h>\n#import \"ObjcBaseTestCase.h\"\n\n@interface ObjCCryptoUtilsTests : ObjcBaseTestCase\n\n@end\n\n@implementation ObjCCryptoUtilsTests\n\n- (void)setUp {\n    [super setUp];\n}\n\n- (void)tearDown {\n    [super tearDown];\n}\n\n// MARK: - SHA256\n- (void)test_SHA256Base64_emptyString_shouldReturnHashedString {\n    \n    // Given\n    NSString* initialString = @\"\";\n    \n    NSString* expectedResult = @\"47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU\";\n    \n    // When\n    NSString* actualResult = [CryptoObjcHelper sha256_base64WithString:initialString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, @\"Hashed string should not be nil\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Hashed string should be equal to expected result\");\n}\n- (void)test_SHA256Base64_specialString_shouldReturnHashedString {\n    \n    // Given\n    NSString* initialString = @\"🧼:|}!@#$%^&*()±§`~+_=-\";\n    \n    NSString* expectedResult = @\"jXJPEpRxcbKlIzNzH1RzAsaDeDR87Ir0cENeW8b5t-g\";\n    \n    // When\n    NSString* actualResult = [CryptoObjcHelper sha256_base64WithString:initialString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, @\"Hashed string should not be nil\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Hashed string should be equal to expected result\");\n}\n- (void)test_SHA256Base64_string_shouldReturnHashedString {\n    \n    // Given\n    NSString* initialString = @\"cryptoString\";\n    \n    NSString* expectedResult = @\"Ncsntkv4ywCQbf4Xz3pTYrxglVm02y4_X9nmCR8uNt0\";\n    \n    // When\n    NSString* actualResult = [CryptoObjcHelper sha256_base64WithString:initialString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, @\"Hashed string should not be nil\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Hashed string should be equal to expected result\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/CryptoUtilsTests/CryptoUtilsTests.swift",
    "content": "//\n//  CryptoUtilsTests.swift\n//  CloudinaryTests\n//\n//  Created by Nitzan Jaitman on 14/11/2017.\n//  Copyright © 2017 Cloudinary. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import Cloudinary\n\n@objc \n@objcMembers\npublic class CryptoObjcHelper: NSObject {\n    \n    @objc public class func sha256_base64(string: String) -> String {\n        return string.sha256_base64()\n    }\n}\n\nclass CryptoUtilsTests: BaseTestCase {\n    override func setUp() {\n        super.setUp()\n    }\n    \n    override func tearDown() {\n        super.tearDown()\n    }\n    \n    // MARK: - MD5\n    func testMd5() {\n        let md5 = \"sadnkjqndlk3j43qdaoni834j032df8j0a9sdfu03124\".cld_md5()\n        XCTAssertEqual(\"e75465c18b05f1a7e665bbafa9266ef4\", md5)\n    }\n    \n    // MARK - SHA1\n    func testSha1Base8(){\n        let value = \"sadnkjqndlk3j43qdaoni834j032df8j0a9sdfu03124\"\n        let secret = \"rnkjd123af43214na\"\n        let shar1WithSecret = value.sha1_base8(secret)\n        let sha1 = value.sha1_base8(nil)\n        \n        XCTAssertEqual(\"6aab31b1ad46b21ba8b1a64d451a762395ae222a\", shar1WithSecret)\n        XCTAssertEqual(\"89f30d95fd5e83ce93247677e4a301e279a48ca2\", sha1)\n    }\n    \n    func testSha1Base64(){\n        let value = \"sadnkjqndlk3j43qdaoni834j032df8j0a9sdfu03124\"\n        let sha1 = value.sha1_base64()\n        \n        XCTAssertEqual(\"ifMNlf1eg86TJHZ35KMB4nmkjKI\", sha1)\n    }\n    \n    // MARK: - SHA256\n    func test_SHA256Base64_emptyString_shouldReturnHashedString() {\n        \n        // Given\n        let initialString  = \"\"\n        \n        let expectedResult = \"47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU\"\n        \n        // When\n        let actualResult = initialString.sha256_base64()\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"Hashed string should not be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"Hashed string should be equal to expected result\")\n    }\n    func test_SHA256Base64_specialString_shouldReturnHashedString() {\n        \n        // Given\n        let initialString  = \"🧼:|}!@#$%^&*()±§`~+_=-\"\n        \n        let expectedResult = \"jXJPEpRxcbKlIzNzH1RzAsaDeDR87Ir0cENeW8b5t-g\"\n        \n        // When\n        let actualResult = initialString.sha256_base64()\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"Hashed string should not be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"Hashed string should be equal to expected result\")\n    }\n    func test_SHA256Base64_string_shouldReturnHashedString() {\n        \n        // Given\n        let initialString  = \"cryptoString\"\n        \n        let expectedResult = \"Ncsntkv4ywCQbf4Xz3pTYrxglVm02y4_X9nmCR8uNt0\"\n        \n        // When\n        let actualResult = initialString.sha256_base64()\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"Hashed string should not be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"Hashed string should be equal to expected result\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/FileUtilsTests.swift",
    "content": "//\n//  FileUtilsTests.swift\n//  CloudinaryTests\n//\n//  Created by Nitzan Jaitman on 24/09/2017.\n//  Copyright © 2017 Cloudinary. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import Cloudinary\n\nclass FileUtilsTests: BaseTestCase {\n    override func setUp() {\n        super.setUp()\n    }\n    \n    override func tearDown() {\n        super.tearDown()\n    }\n    \n    func testSplitFile() {\n        \n        let url = Bundle(for: FileUtilsTests.self).url(forResource: \"borderCollie\", withExtension: \"jpg\")!\n        let (_, files) = CLDFileUtils.splitFile(url: url, chunkSize: 1024 * 20)!\n        let totalSize = CLDFileUtils.getFileSize(url: url)\n        \n        var sum: Int64 = 0\n        \n        for file in files {\n            XCTAssertTrue(FileManager.default.fileExists(atPath: file.url.path))\n            sum += Int64(file.length)\n        }\n        \n        XCTAssertEqual(sum, totalSize)\n    }\n    \n    func testRemoveFiles(){\n        let url = Bundle.init(for: FileUtilsTests.self).url(forResource: \"borderCollie\", withExtension: \"jpg\")!\n        let (base, files) = CLDFileUtils.splitFile(url: url, chunkSize: 1024 * 20)!\n        \n        for file in files {\n            XCTAssertTrue(FileManager.default.fileExists(atPath: file.url.path))\n        }\n        \n        CLDFileUtils.removeFile(file: base!)\n        XCTAssertFalse(FileManager.default.fileExists(atPath: base!.path))\n        \n        \n    }\n}\n"
  },
  {
    "path": "Example/Tests/GenerateUrlTests/UrlTests.m",
    "content": "//\n//  ObjCUrlTests.m\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"ObjcBaseTestCase.h\"\n\n@interface ObjCUrlTests : ObjcBaseTestCase\n@property (nonatomic, strong, nullable) CLDCloudinary *sut;\n@end\n\n@implementation ObjCUrlTests\n\nNSString* prefix = @\"https://res.cloudinary.com/test123\";\n\n- (void)setUp {\n    [super setUp];\n    CLDConfiguration *config = [[CLDConfiguration alloc] initWithCloudinaryUrl:@\"cloudinary://a:b@test123?analytics=false\"];\n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n}\n\n- (void)tearDown {\n    [super tearDown];\n    self.sut = nil;\n}\n\n- (void)testCrop {\n    CLDTransformation *trans = [[CLDTransformation alloc]init];\n    [trans setWidth:@\"100\"];\n    [trans setHeight:@\"101\"];\n    [trans setCrop:@\"crop\"];\n\n    CLDUrl *url = [self.sut createUrl];\n    [url setTransformation:trans];\n    NSString *generatedUrl = [url generate:@\"test\" signUrl:NO];\n    XCTAssertEqualObjects(generatedUrl, [prefix stringByAppendingString: @\"/image/upload/c_crop,h_101,w_100/test\"]);\n}\n// MARK: - gravity\n- (void)test_gravityEnum_shouldReturnExpectedValues {\n    \n    [self testGravityUrl:CLDGravityCenter expectedValue:@\"g_center,w_100\"];\n    [self testGravityUrl:CLDGravityAuto expectedValue:@\"g_auto,w_100\"];\n    [self testGravityUrl:CLDGravityFace expectedValue:@\"g_face,w_100\"];\n    [self testGravityUrl:CLDGravityFaceCenter expectedValue:@\"g_face:center,w_100\"];\n    [self testGravityUrl:CLDGravityFaces expectedValue:@\"g_faces,w_100\"];\n    [self testGravityUrl:CLDGravityFacesCenter expectedValue:@\"g_faces:center,w_100\"];\n    [self testGravityUrl:CLDGravityAdvFace expectedValue:@\"g_adv_face,w_100\"];\n    [self testGravityUrl:CLDGravityAdvFaces expectedValue:@\"g_adv_faces,w_100\"];\n    [self testGravityUrl:CLDGravityAdvEyes expectedValue:@\"g_adv_eyes,w_100\"];\n    [self testGravityUrl:CLDGravityNorth expectedValue:@\"g_north,w_100\"];\n    [self testGravityUrl:CLDGravityNorthWest expectedValue:@\"g_north_west,w_100\"];\n    [self testGravityUrl:CLDGravityNorthEast expectedValue:@\"g_north_east,w_100\"];\n    [self testGravityUrl:CLDGravitySouth expectedValue:@\"g_south,w_100\"];\n    [self testGravityUrl:CLDGravitySouthWest expectedValue:@\"g_south_west,w_100\"];\n    [self testGravityUrl:CLDGravitySouthEast expectedValue:@\"g_south_east,w_100\"];\n    [self testGravityUrl:CLDGravityWest expectedValue:@\"g_west,w_100\"];\n    [self testGravityUrl:CLDGravityEast expectedValue:@\"g_east,w_100\"];\n    [self testGravityUrl:CLDGravityXyCenter expectedValue:@\"g_xy_center,w_100\"];\n    [self testGravityUrl:CLDGravityCustom expectedValue:@\"g_custom,w_100\"];\n    [self testGravityUrl:CLDGravityCustomFace expectedValue:@\"g_custom:face,w_100\"];\n    [self testGravityUrl:CLDGravityCustomFaces expectedValue:@\"g_custom:faces,w_100\"];\n    [self testGravityUrl:CLDGravityCustomAdvFace expectedValue:@\"g_custom:adv_face,w_100\"];\n    [self testGravityUrl:CLDGravityCustomAdvFaces expectedValue:@\"g_custom:adv_faces,w_100\"];\n    [self testGravityUrl:CLDGravityAutoOcrText expectedValue:@\"g_auto:ocr_text,w_100\"];\n    [self testGravityUrl:CLDGravityOcrText expectedValue:@\"g_ocr_text,w_100\"];\n    [self testGravityUrl:CLDGravityOcrTextAdvOcr expectedValue:@\"g_ocr_text:adv_ocr,w_100\"];\n}\n- (void)testGravityUrl:(CLDGravity)gravity expectedValue:(NSString*)expectedValue {\n   \n    // Given\n    NSString* inputWidth    = @\"100\";\n    NSString* inputPublicId = @\"publicId\";\n    BOOL      inputSignUrl  = false;\n    \n    NSString* expectedResult = [NSString stringWithFormat:@\"%@/image/upload/%@/%@\", prefix, expectedValue, inputPublicId];\n    \n    // When\n    CLDTransformation* transformation = [[[[CLDTransformation alloc] init] setWidth:inputWidth] setGravityWithGravity:gravity];\n    NSString* actualResult = [[[self.sut createUrl] setTransformation:transformation] generate:inputPublicId signUrl:inputSignUrl];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, @\"Creating url with gravity enum should return expected result\");\n}\n\n// MARK: - long url signing\n- (void)test_longUrlSign_emptyApiSecret_shouldCreateExpectedSigning {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:YES\n                                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                                          signatureVersion: 2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                   analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n     \n    NSString* expectedResult = @\"DUB-5kBqEhbyNmZ0oan_cTYdW-9HAh-O\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 32, \"encrypted component should not be longer than 32 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration with longUrlSignature = YES and call generate with signUrl = YES, should encrypt the ApiSecret with SHA256_base64\");\n}\n- (void)test_longUrlSign_normalApiSecret_shouldCreateExpectedSigning {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"apiSecret\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:YES\n                                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n\n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n     \n    NSString* expectedResult = @\"UHH8qJ2eIEoPHdVQP08BMEN9f4YUDavr\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 32, \"encrypted component should not be longer than 32 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration with longUrlSignature = YES and call generate with signUrl = YES, should encrypt the ApiSecret with SHA256_base64\");\n}\n- (void)test_longUrlSign_longApiSecret_shouldCreateExpectedSigning {\n    \n    // Given\n    NSString* longString = @\"abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz2abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz4abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz6\";\n\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:longString\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:YES\n                                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n\n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n    \n    NSString* expectedResult = @\"7k8KYHY20iQ6sNTJIWb05ti7bYo1HG3R\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 32, \"encrypted component should not be longer than 32 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration with longUrlSignature and call generate with signUrl = YES, should encrypt the ApiSecret with SHA256_base64\");\n}\n- (void)test_longUrlSign_specialApiSecret_shouldCreateExpectedSigning {\n    \n    // Given\n    NSString* specialString = @\"🔭!@#$%^&*()_+±§?><`~\";\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:specialString\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:YES\n                                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n\n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:true];\n     \n    NSString* expectedResult = @\"g12ptQdGPID3Un4aOxZSuiEithIdT2Wm\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 32, \"encrypted component should not be longer than 32 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration with longUrlSignature and call generate with signUrl = YES, should encrypt the ApiSecret with SHA256_base64\");\n}\n- (void)test_longUrlSign_unset_shouldCreateExpectedSigning {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"apiSecret\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:NO\n                                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n     \n    NSString* expectedResult = @\"FhXe8ZZ3\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 8, \"encrypted component should not be longer than 8 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration with longUrlSignature = NO and call generate with signUrl = YES, should encrypt the ApiSecret with SHA1_base64\");\n}\n- (void)test_longUrlSign_signUrlFalse_shouldCreateExpectedSigning {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"apiSecret\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:YES\n                                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:NO];\n     \n    NSString* expectedResult = @\"http://test123-res.cloudinary.com/image/upload/test.jpg\";\n    \n    // When\n    NSString* actualResult = url;\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration with longUrlSignature = YES and call generate with signUrl = NO, should not encrypt and add the ApiSecret to the url\");\n}\n- (void)test_longUrlSign_unset_shouldCreateExpectedUrl {\n    \n    // Given\n    NSString* url = [[self.sut createUrl] generate:@\"sample.jpg\" signUrl:YES];\n     \n    NSString* expectedResult = @\"https://res.cloudinary.com/test123/image/upload/s--v2fTPYTu--/sample.jpg\";\n    \n    // When\n    NSString* actualResult = url;\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration with longUrlSignature = NO and call generate with signUrl = YES, should create a url with SHA1 encrypted apiSecret\");\n}\n- (void)test_longUrlSign_true_shouldCreateExpectedUrl {\n    \n    // Given\n    NSString* longUrlSignatureQuery = @\"?long_url_signature=true&analytics=false\";\n    NSString* urlCredentials        = @\"cloudinary://a:b@test123\";\n    NSString* fullUrl               = [NSString stringWithFormat:@\"%@%@\",urlCredentials,longUrlSignatureQuery];\n    \n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudinaryUrl:fullUrl];\n\n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[self.sut createUrl] generate:@\"sample.jpg\" signUrl:YES];\n     \n    NSString* expectedResult = @\"https://res.cloudinary.com/test123/image/upload/s--2hbrSMPOjj5BJ4xV7SgFbRDevFaQNUFf--/sample.jpg\";\n    \n    // When\n    NSString* actualResult = url;\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration with longUrlSignature = YES and call generate with signUrl = YES, should create a url with SHA256 encrypted apiSecret\");\n}\n\n// MARK: - signature algorithm\n-(void)test_signatureAlgorithm_emptyApiSecret_shouldCreateExpectedSigning {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:NO\n                                                        signatureAlgorithm:SignatureAlgorithmSha256\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n     \n    NSString* expectedResult = @\"DUB-5kBq\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 8, \"encrypted component should not be longer than 8 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and call for signUrl = YES, should ecrypte with SHA256_base64\");\n}\n- (void)test_signatureAlgorithm_normalApiSecret_shouldCreateExpectedSigning {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"apiSecret\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:NO\n                                                        signatureAlgorithm:SignatureAlgorithmSha256\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n     \n    NSString* expectedResult = @\"UHH8qJ2e\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 8, \"encrypted component should not be longer than 8 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and call for signUrl = YES, should ecrypte with SHA256_base64\");\n}\n- (void)test_signatureAlgorithm_longApiSecret_shouldCreateExpectedSigning {\n    \n    // Given\n    NSString* longString = @\"abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz2abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz4abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz6\";\n    \n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:longString\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:NO\n                                                        signatureAlgorithm:SignatureAlgorithmSha256\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n                                                       \n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n     \n    NSString* expectedResult = @\"7k8KYHY2\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 8, \"encrypted component should not be longer than 8 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and call for signUrl = YES, should ecrypte with SHA256_base64\");\n}\n- (void)test_signatureAlgorithm_specialApiSecret_shouldCreateExpectedSigning {\n    \n    // Given\n    NSString* specialString = @\"🔭!@#$%^&*()_+±§?><`~\";\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:specialString\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:NO\n                                                        signatureAlgorithm:SignatureAlgorithmSha256\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n     \n    NSString* expectedResult = @\"g12ptQdG\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 8, \"encrypted component should not be longer than 8 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and call for signUrl = YES, should ecrypte with SHA256_base64\");\n}\n- (void)test_signatureAlgorithm_unset_shouldCreateExpectedSigning {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"apiSecret\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:NO\n                                                        signatureAlgorithm:0\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n     \n    NSString* expectedResult = @\"FhXe8ZZ3\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 8, \"encrypted component should not be longer than 8 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration without signatureAlgorithm and call for signUrl = true, should ecrypte with the default SHA1_base64\");\n}\n- (void)test_signatureAlgorithm_signUrlFalse_shouldCreateFullUrlWithoutSigning {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"apiSecret\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:NO\n                                                        signatureAlgorithm:SignatureAlgorithmSha256\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:NO];\n     \n    NSString* expectedResult = @\"http://test123-res.cloudinary.com/image/upload/test.jpg\";\n    \n    // When\n    NSString* actualResult = url;\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and call for signUrl = false, should not encrypt nor add the ApiSecret to the url\");\n}\n- (void)test_signatureAlgorithm_unset_shouldCreateExpectedFullUrl {\n    \n    // Given\n    NSString* url = [[self.sut createUrl] generate:@\"sample.jpg\" signUrl:YES];\n     \n    NSString* expectedResult = @\"https://res.cloudinary.com/test123/image/upload/s--v2fTPYTu--/sample.jpg\";\n    \n    // When\n    NSString* actualResult = url;\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration for default signatureAlgorithm and signUrl = true, should create a url with SHA1 encrypted apiSecret\");\n}\n- (void)test_signatureAlgorithm_sha256_shouldCreateExpectedFullUrl {\n    \n    // Given\n    NSString* signatureAlgorithQuery = @\"?signature_algorithm=sha256&analytics=false\";\n    NSString* urlCredentials        = @\"cloudinary://a:b@test123\";\n    NSString* fullUrl               = [NSString stringWithFormat:@\"%@%@\",urlCredentials,signatureAlgorithQuery];\n    \n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudinaryUrl:fullUrl];\n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[self.sut createUrl] generate:@\"sample.jpg\" signUrl:YES];\n     \n    NSString* expectedResult = @\"https://res.cloudinary.com/test123/image/upload/s--2hbrSMPO--/sample.jpg\";\n    \n    // When\n    NSString* actualResult = url;\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and signUrl = true, should create a url with SHA256 encrypted apiSecret\");\n}\n\n// MARK: - signing combinations\n- (void)test_signingCombinations_signTrueLongTrueAlgorithmSha1_shouldUse32CharsEcryptedSha256 {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"apiSecret\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:YES\n                                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n     \n    NSString* expectedResult = @\"UHH8qJ2eIEoPHdVQP08BMEN9f4YUDavr\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 32, \"encrypted component should not be longer than 32 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"longUrlSignature should override signing algorithm and force sha256 with 32 charecters\");\n}\n- (void)test_signingCombinations_signTrueLongTrueAlgorithmSha256_shouldUse32CharsEcryptedSha256 {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"apiSecret\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:YES\n                                                        signatureAlgorithm:SignatureAlgorithmSha256\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:YES];\n     \n    NSString* expectedResult = @\"UHH8qJ2eIEoPHdVQP08BMEN9f4YUDavr\";\n    \n    // When\n    NSString* actualResult = [url componentsSeparatedByString:@\"--\"][1];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"encrypted component should not be nil\");\n    XCTAssertTrue(actualResult.length <= 32, \"encrypted component should not be longer than 32 charecters\");\n    XCTAssertEqualObjects(actualResult, expectedResult, \"longUrlSignature should override signing algorithm and force sha256 with 32 charecters\");\n}\n- (void)test_signingCombinations_signFalseLongTrueAlgorithmSha1_shouldNotUseSigning {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"apiSecret\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:YES\n                                                        signatureAlgorithm:SignatureAlgorithmSha1\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:NO];\n     \n    NSString* expectedResult = @\"http://test123-res.cloudinary.com/image/upload/test.jpg\";\n    \n    // When\n    NSString* actualResult = url;\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and longUrlSignature = true and call for signUrl = false, should not encrypt nor add the ApiSecret to the url\");\n}\n- (void)test_signingCombinations_signFalseLongTrueAlgorithmSha256_shouldUseSigning {\n    \n    // Given\n    CLDConfiguration* config = [[CLDConfiguration alloc] initWithCloudName:@\"test123\"\n                                                                    apiKey:@\"apiKey\"\n                                                                 apiSecret:@\"apiSecret\"\n                                                                privateCdn:YES\n                                                                    secure:NO\n                                                              cdnSubdomain:NO\n                                                        secureCdnSubdomain:NO\n                                                          longUrlSignature:YES\n                                                        signatureAlgorithm:SignatureAlgorithmSha256\n                                                          signatureVersion:2\n                                                        secureDistribution:nil\n                                                                     cname:nil\n                                                              uploadPrefix:nil\n                                                                   timeout:nil\n                                                                 analytics:NO];\n    \n    self.sut = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:nil];\n    NSString* url = [[[self.sut createUrl] setFormat:@\"jpg\"] generate:@\"test\" signUrl:NO];\n     \n    NSString* expectedResult = @\"http://test123-res.cloudinary.com/image/upload/test.jpg\";\n    \n    // When\n    NSString* actualResult = url;\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and longUrlSignature = true and call for signUrl = false, should not encrypt nor add the ApiSecret to the url\");\n}\n\n// MARK: - named spaces removal\n- (void)test_replaceSpaces_named_shouldCreateExpectedUrl {\n    \n    // Given\n    NSString* inputWidth    = @\"100\";\n    NSString* inputHeight   = @\"200\";\n    NSString* inputNamed    = @\"named\";\n    NSString* inputPublicId = @\"publicId\";\n    BOOL      inputSignUrl  = false;\n    \n    NSString* expectedResult = @\"https://res.cloudinary.com/test123/image/upload/h_200,t_named,w_100/publicId\";\n    \n    // When\n    CLDTransformation* transformation = [[[[[CLDTransformation alloc] init] setWidth:inputWidth] setNamed:inputNamed] setHeight:inputHeight];\n    NSString* actualResult            = [[[self.sut createUrl] setTransformation:transformation] generate:inputPublicId signUrl:inputSignUrl];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, @\"creating url with named in transformation should return the expected result\");\n}\n- (void)test_replaceSpaces_namedWithSpaces_shouldReplaceSpaces {\n    \n    // Given\n    NSString* inputWidth       = @\"100\";\n    NSString* inputHeight      = @\"200\";\n    NSString* inputSpacedNamed = @\"named with spaces\";\n    NSString* inputPublicId    = @\"publicId\";\n    BOOL      inputSignUrl     = false;\n    \n    NSString* expectedResult = @\"https://res.cloudinary.com/test123/image/upload/h_200,t_named%20with%20spaces,w_100/publicId\";\n    \n    // When\n    CLDTransformation* transformation = [[[[[CLDTransformation alloc] init] setWidth:inputWidth] setNamed:inputSpacedNamed] setHeight:inputHeight];\n    NSString* actualResult            = [[[self.sut createUrl] setTransformation:transformation] generate:inputPublicId signUrl:inputSignUrl];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, @\"creating url with named in transformation should return the expected result\");\n    \n}\n- (void)test_replaceSpaces_namedArray_shouldCreateExpectedUrl {\n    \n    // Given\n    NSString* inputWidth    = @\"100\";\n    NSString* inputHeight   = @\"200\";\n    NSString* inputNamed1   = @\"named1\";\n    NSString* inputNamed2   = @\"named2\";\n    NSString* inputPublicId = @\"publicId\";\n    BOOL      inputSignUrl  = false;\n    \n    NSString* expectedResult = @\"https://res.cloudinary.com/test123/image/upload/h_200,t_named1.named2,w_100/publicId\";\n    \n    // When\n    CLDTransformation* transformation = [[[[[CLDTransformation alloc] init] setWidth:inputWidth] setNamedWithArray:@[inputNamed1,inputNamed2]] setHeight:inputHeight];\n    NSString* actualResult            = [[[self.sut createUrl] setTransformation:transformation] generate:inputPublicId signUrl:inputSignUrl];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, @\"creating url with named in transformation should return the expected result\");\n}\n- (void)test_replaceSpaces_namedArrayWithSpaces_shouldReplaceSpaces {\n    \n    // Given\n    NSString* inputWidth        = @\"100\";\n    NSString* inputHeight       = @\"200\";\n    NSString* inputSpacedNamed1 = @\"named with spaces 1\";\n    NSString* inputSpacedNamed2 = @\"named with spaces 2\";\n    NSString* inputPublicId     = @\"publicId\";\n    BOOL      inputSignUrl      = false;\n    \n    NSString* expectedResult = @\"https://res.cloudinary.com/test123/image/upload/h_200,t_named%20with%20spaces%201.named%20with%20spaces%202,w_100/publicId\";\n    \n    // When\n    CLDTransformation* transformation = [[[[[CLDTransformation alloc] init] setWidth:inputWidth] setNamedWithArray:@[inputSpacedNamed1,inputSpacedNamed2]] setHeight:inputHeight];\n    NSString* actualResult            = [[[self.sut createUrl] setTransformation:transformation] generate:inputPublicId signUrl:inputSignUrl];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, @\"creating url with named in transformation should return the expected result\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/GenerateUrlTests/UrlTests.swift",
    "content": "//\n//  UrlTests.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\nclass UrlTests: BaseTestCase {\n    let prefix = \"https://res.cloudinary.com/test123\"\n\n    var sut: CLDCloudinary?\n\n    override func setUp() {\n        super.setUp()\n        let config = CLDConfiguration(cloudinaryUrl: \"cloudinary://a:b@test123?analytics=false\")!\n        sut = CLDCloudinary(configuration: config)\n    }\n\n    override func tearDown() {\n        super.tearDown()\n        sut = nil\n    }\n\n    func testParseCloudinaryUrlNoPrivateCdn() {\n        let config = CLDConfiguration(cloudinaryUrl: \"cloudinary://abc:def@ghi\")\n\n        XCTAssertEqual(config?.apiKey, \"abc\")\n        XCTAssertEqual(config?.apiSecret, \"def\")\n        XCTAssertEqual(config?.cloudName, \"ghi\")\n        XCTAssertEqual(config?.privateCdn, false)\n    }\n\n    func testParseCloudinaryUrlWithPrivateCdn() {\n        let config = CLDConfiguration(cloudinaryUrl: \"cloudinary://abc:def@ghi/jkl\")\n\n        XCTAssertEqual(config?.apiKey, \"abc\")\n        XCTAssertEqual(config?.apiSecret, \"def\")\n        XCTAssertEqual(config?.cloudName, \"ghi\")\n        XCTAssertEqual(config?.privateCdn, true)\n        XCTAssertEqual(config?.secureDistribution, \"jkl\")\n    }\n\n    func testCloudName() {\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/test\")\n    }\n    \n   func testCloudinaryUrlValidScheme() {\n       let isValid = CLDConfiguration.validateUrl(url: \"cloudinary://123456789012345:ALKJdjklLJAjhkKJ45hBK92baj3@test\")\n       XCTAssertTrue(isValid);\n    }\n    \n    func testCloudinaryUrlInvalidScheme() {\n       let isValid = CLDConfiguration.validateUrl(url: \"https://123456789012345:ALKJdjklLJAjhkKJ45hBK92baj3@test\")\n       XCTAssertFalse(isValid);\n    }\n     \n    func testCloudinaryUrlEmptyScheme() {\n        let isValid = CLDConfiguration.validateUrl(url: \"\")\n        XCTAssertFalse(isValid);\n    }\n\n    func testInitConfiguration(){\n        let config = CLDConfiguration(cloudinaryUrl: \"https://123456789012345:ALKJdjklLJAjhkKJ45hBK92baj3@test\")\n        XCTAssertEqual(config, nil)\n        \n        let config2 = CLDConfiguration(cloudinaryUrl: \"cloudinary://123456789012345:ALKJdjklLJAjhkKJ45hBK92baj3@test\")\n        XCTAssertNotNil(config2)\n    }\n\n    func testSecure() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", secure: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/test\")\n    }\n\n    func testSecureDistribution() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", secure: true, secureDistribution: \"something.else.com\", analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"https://something.else.com/test123/image/upload/test\")\n    }\n\n    func testSecureAkamai() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, secure: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"https://test123-res.cloudinary.com/image/upload/test\")\n    }\n\n    func testSecureNonAkamai() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, secure: true, secureDistribution: \"something.cloudfront.net\", analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"https://something.cloudfront.net/image/upload/test\")\n    }\n\n    func testHttpPrivateCdn() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"http://test123-res.cloudinary.com/image/upload/test\")\n    }\n\n    func testCdnSubDomain() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", cdnSubdomain: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"http://res-2.cloudinary.com/test123/image/upload/test\")\n    }\n\n    func testSecureCdnSubDomainFalse() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", secure: true, cdnSubdomain: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/test\")\n    }\n\n    func testSecureCdnSubDomainTrue() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, secure: true, cdnSubdomain: true, secureCdnSubdomain: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"https://test123-res-2.cloudinary.com/image/upload/test\")\n    }\n\n    func testAnalyticsTrue() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, secure: true, cdnSubdomain: true, secureCdnSubdomain: true, analytics: true)\n        config.analyticsObject.setSDKVersion(version: \"3.3.0\")\n        config.analyticsObject.setTechVersion(version: \"5.0\")\n        config.analyticsObject.setOsVersion(version: \"17.0\")\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"https://test123-res-2.cloudinary.com/image/upload/test?_a=DAEAEvAFBRA0\")\n    }\n\n    func testFormat() {\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/test.jpg\")\n    }\n\n    func testCrop() {\n        let trans = CLDTransformation().setWidth(100).setHeight(101)\n        var url = sut?.createUrl().setTransformation(trans).generate(\"test\")\n\n        url = sut?.createUrl().setTransformation(CLDTransformation().setWidth(100).setHeight(101).setCrop(.crop)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_crop,h_101,w_100/test\")\n    }\n\n    func testVariousOptions() {\n        let url = sut?.createUrl().setTransformation(CLDTransformation().setX(1).setY(2).setRadius(3).setGravity(.center).setQuality(\"0.4\").setPrefix(\"a\")).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/g_center,p_a,q_0.4,r_3,x_1,y_2/test\")\n        let urlRadius = sut?.createUrl().setTransformation(CLDTransformation().setX(1).setY(2).setRadius([10,20,\"30\",\"$v\"]).setGravity(.center).setQuality(\"0.4\").setPrefix(\"a\")).generate(\"test\")\n        XCTAssertEqual(urlRadius, \"\\(prefix)/image/upload/g_center,p_a,q_0.4,r_10:20:30:$v,x_1,y_2/test\")\n        let urlRadius2 = sut?.createUrl().setTransformation(CLDTransformation().setX(1).setY(2).setRadius([20,0,\"3\"]).setGravity(.center).setQuality(\"0.4\").setPrefix(\"a\")).generate(\"test\")\n        XCTAssertEqual(urlRadius2, \"\\(prefix)/image/upload/g_center,p_a,q_0.4,r_20:0:3,x_1,y_2/test\")\n    }\n\n    func testQuality() {\n        let urlAuto = sut?.createUrl().setTransformation(CLDTransformation().setX(1).setY(2).setRadius(3).setGravity(.center).setQuality(.auto()).setPrefix(\"a\")).generate(\"test\")\n        XCTAssertEqual(urlAuto, \"\\(prefix)/image/upload/g_center,p_a,q_auto,r_3,x_1,y_2/test\")\n\n        let urlEco = sut?.createUrl().setTransformation(CLDTransformation().setX(1).setY(2).setRadius(3).setGravity(.center).setQuality(.auto(.eco)).setPrefix(\"a\")).generate(\"test\")\n        XCTAssertEqual(urlEco, \"\\(prefix)/image/upload/g_center,p_a,q_auto:eco,r_3,x_1,y_2/test\")\n\n        let urlFixed = sut?.createUrl().setTransformation(CLDTransformation().setX(1).setY(2).setRadius(3).setGravity(.center).setQuality(.fixed(50)).setPrefix(\"a\")).generate(\"test\")\n        XCTAssertEqual(urlFixed, \"\\(prefix)/image/upload/g_center,p_a,q_50,r_3,x_1,y_2/test\")\n\n        let urlJpegMini = sut?.createUrl().setTransformation(CLDTransformation().setX(1).setY(2).setRadius(3).setGravity(.center).setQuality(.jpegMini()).setPrefix(\"a\")).generate(\"test\")\n        XCTAssertEqual(urlJpegMini, \"\\(prefix)/image/upload/g_center,p_a,q_jpegmini,r_3,x_1,y_2/test\")\n    }\n\n    func testTransformationSimple() {\n        let url = sut?.createUrl().setTransformation(CLDTransformation().setNamed([\"blip\"])).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/t_blip/test\")\n    }\n\n    func testTransformationArray() {\n        let url = sut?.createUrl().setTransformation(CLDTransformation().setNamed([\"blip\", \"blop\"])).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/t_blip.blop/test\")\n    }\n\n    func testBaseTransformations() {\n        let url = sut?.createUrl().setTransformation(CLDTransformation().setX(100).setY(100).setCrop(.fill).chain().setCrop(.crop).setWidth(100)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_fill,x_100,y_100/c_crop,w_100/test\")\n    }\n    \n    func testContextMetadataToUserVariables() {\n        let url = sut?.createUrl().setTransformation(CLDTransformation()\n                                                        .setVariable(CLDVariable(name: \"$xpos\", value: \"ctx:!x_pos!_to_f\"))\n                                                        .setVariable(CLDVariable(name: \"$ypos\", value: \"ctx:!y_pos!_to_f\"))\n                                                        .setCrop(\"crop\")\n                                                        .setX(\"$xpos * w\")\n                                                        .setY(\"$ypos * h\")).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/$xpos_ctx:!x_pos!_to_f,$ypos_ctx:!y_pos!_to_f,c_crop,x_$xpos_mul_w,y_$ypos_mul_h/test\")\n    }\n\n    func testBaseTransformationArray() {\n        let url = sut?.createUrl().setTransformation(CLDTransformation().setX(100).setY(100).setWidth(200).setCrop(.fill).chain().setRadius(10).chain().setCrop(.crop).setWidth(100)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_fill,w_200,x_100,y_100/r_10/c_crop,w_100/test\")\n    }\n    \n    func test_CLDTransformation_setCrop_validUrl() {\n        var url : String?\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.fill)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_fill/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.crop)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_crop/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.scale)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_scale/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.fit)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_fit/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.limit)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_limit/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.mFit)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_mfit/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.lFill)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_lfill/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.pad)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_pad/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.lPad)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_lpad/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.mPad)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_mpad/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.thumb)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_thumb/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.imaggaCrop)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_imagga_crop/test\")\n        \n        url = sut?.createUrl().setTransformation(CLDTransformation().setCrop(.imaggaScale)).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_imagga_scale/test\")\n    }\n\n    func testNoEmptyTransformation() {\n        let url = sut?.createUrl().setTransformation(CLDTransformation().setX(100).setY(100).setCrop(.fill).chain()).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/upload/c_fill,x_100,y_100/test\")\n    }\n\n    func testType() {\n        let url = sut?.createUrl().setType(.facebook).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/image/facebook/test\")\n    }\n\n    func testResourceType() {\n        let url = sut?.createUrl().setResourceType(.raw).generate(\"test\")\n        XCTAssertEqual(url, \"\\(prefix)/raw/upload/test\")\n    }\n\n    func testFetch() {\n        let url = sut?.createUrl().setType(.fetch).generate(\"http://blah.com/hello?a=b\")\n        XCTAssertEqual(url, \"\\(prefix)/image/fetch/http://blah.com/hello%3Fa%3Db\")\n    }\n\n    func testCname() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", cname: \"hello.com\", analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"http://hello.com/test123/image/upload/test\")\n    }\n\n    func testCnameSubdomain() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", cdnSubdomain: true, cname: \"hello.com\", analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().generate(\"test\")\n        XCTAssertEqual(url, \"http://a2.hello.com/test123/image/upload/test\")\n    }\n\n    func testUrlSuffixShared() {\n        XCTAssertNil(sut?.createUrl().setSuffix(\"hello\").generate(\"test\"))\n    }\n\n    func testUrlSuffixNonUpload() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true)\n        sut = CLDCloudinary(configuration: config)\n        XCTAssertNil(sut?.createUrl().setType(.facebook).setSuffix(\"hello\").generate(\"test\"))\n    }\n\n    func testUrlSuffixDisallowedChars() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true)\n        sut = CLDCloudinary(configuration: config)\n        XCTAssertNil(sut?.createUrl().setSuffix(\"hello/world\").generate(\"test\"))\n        XCTAssertNil(sut?.createUrl().setSuffix(\"hello.world\").generate(\"test\"))\n    }\n\n    func testUrlSuffixPrivateCdn() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        XCTAssertEqual(sut?.createUrl().setSuffix(\"hello\").generate(\"test\"), \"http://test123-res.cloudinary.com/images/test/hello\")\n        XCTAssertEqual(sut?.createUrl().setSuffix(\"hello\").setTransformation(CLDTransformation().setAngle(0)).generate(\"test\"), \"http://test123-res.cloudinary.com/images/a_0/test/hello\")\n    }\n\n    func testUrlSuffixFormat() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        XCTAssertEqual(sut?.createUrl().setSuffix(\"hello\").setFormat(\"jpg\").generate(\"test\"), \"http://test123-res.cloudinary.com/images/test/hello.jpg\")\n    }\n\n    func testUrlSuffixSign() {\n        var url1 = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n        var sig1 = url1?.components(separatedBy: \"--\")[1]\n\n        var config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true)\n        sut = CLDCloudinary(configuration: config)\n        var url2 = sut?.createUrl().setSuffix(\"hello\").setFormat(\"jpg\").generate(\"test\", signUrl: true)\n        var sig2 = url2?.components(separatedBy: \"--\")[1]\n\n        XCTAssertEqual(sig1, sig2)\n\n        url1 = sut?.createUrl().setFormat(\"jpg\").setTransformation(CLDTransformation().setAngle(0)).generate(\"test\", signUrl: true)\n        sig1 = url1?.components(separatedBy: \"--\")[1]\n\n        config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true)\n        sut = CLDCloudinary(configuration: config)\n        url2 = sut?.createUrl().setSuffix(\"hello\").setFormat(\"jpg\").setTransformation(CLDTransformation().setAngle(0)).generate(\"test\", signUrl: true)\n        sig2 = url2?.components(separatedBy: \"--\")[1]\n\n        XCTAssertEqual(sig1, sig2)\n    }\n\n    func testUrlSuffixRaw() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        XCTAssertEqual(sut?.createUrl().setSuffix(\"hello\").setResourceType(.raw).generate(\"test\"), \"http://test123-res.cloudinary.com/files/test/hello\")\n    }\n\n    func testUrlSuffixPrivate() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        XCTAssertEqual(sut?.createUrl().setSuffix(\"hello\").setResourceType(.image).setType(.private).generate(\"test\"), \"http://test123-res.cloudinary.com/private_images/test/hello\")\n    }\n    \n    // MARK: - long url signature\n    func test_longUrlSign_emptyApiSecret_shouldCreateExpectedSigning() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"\", privateCdn: true, longUrlSignature: true)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"DUB-5kBqEhbyNmZ0oan_cTYdW-9HAh-O\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 32, \"encrypted component should not be longer than 32 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for longUrlSignature and call for signUrl = true, should encrypt the ApiSecret with SHA256_base64\")\n    }\n    func test_longUrlSign_normalApiSecret_shouldCreateExpectedSigning() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"apiSecret\", privateCdn: true, longUrlSignature: true)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"UHH8qJ2eIEoPHdVQP08BMEN9f4YUDavr\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 32, \"encrypted component should not be longer than 32 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for longUrlSignature and call for signUrl = true, should encrypt the ApiSecret with SHA256_base64\")\n    }\n    func test_longUrlSign_longApiSecret_shouldCreateExpectedSigning() {\n        \n        // Given\n        let longString = \"abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz2abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz4abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz6\"\n        let config = CLDConfiguration(cloudName: \"test123\", apiSecret: longString, privateCdn: true, longUrlSignature: true)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"7k8KYHY20iQ6sNTJIWb05ti7bYo1HG3R\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 32, \"encrypted component should not be longer than 32 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for longUrlSignature and call for signUrl = true, should encrypt the ApiSecret with SHA256_base64\")\n    }\n    func test_longUrlSign_specialApiSecret_shouldCreateExpectedSigning() {\n        \n        // Given\n        let longString = \"🔭!@#$%^&*()_+±§?><`~\"\n        let config = CLDConfiguration(cloudName: \"test123\", apiSecret: longString, privateCdn: true, longUrlSignature: true)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"g12ptQdGPID3Un4aOxZSuiEithIdT2Wm\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 32, \"encrypted component should not be longer than 32 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for longUrlSignature and call for signUrl = true, should encrypt the ApiSecret with SHA256_base64\")\n    }\n    func test_longUrlSign_unset_shouldCreateExpectedSigning() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"apiSecret\", privateCdn: true)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"FhXe8ZZ3\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 8, \"short encrypted component should not be longer than 8 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for longUrlSignature = false and call for signUrl = true, should encrypt the ApiSecret with SHA1_base64\")\n    }\n    func test_longUrlSign_signUrlFalse_shouldNotUseSigning() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"apiSecret\", privateCdn: true, longUrlSignature: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: false)\n         \n        let expectedResult = \"http://test123-res.cloudinary.com/image/upload/test.jpg\"\n        \n        // When\n        let actualResult = url!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for longUrlSignature = true and call for signUrl = false, should not encrypt and add the ApiSecret to the url\")\n    }\n    func test_longUrlSign_unset_shouldCreateExpectedUrl() {\n        \n        // Given\n        let url = sut?.createUrl().generate(\"sample.jpg\", signUrl: true)\n         \n        let expectedResult = \"https://res.cloudinary.com/test123/image/upload/s--v2fTPYTu--/sample.jpg\"\n        \n        // When\n        let actualResult = url!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for longUrlSignature = false and signUrl = true, should create a url with SHA1 encrypted apiSecret\")\n    }\n    func test_longUrlSign_true_shouldCreateExpectedUrl() {\n        \n        // Given\n        let longUrlSignatureQuery = (\"?analytics=false&\\(CLDConfiguration.ConfigParam.LongUrlSignature.description)=true\")\n        let urlCredentials        = \"cloudinary://a:b@test123\"\n        let fullUrl               = urlCredentials + longUrlSignatureQuery\n        \n        let config = CLDConfiguration(cloudinaryUrl: fullUrl)\n        sut = CLDCloudinary(configuration: config!)\n        let url = sut?.createUrl().generate(\"sample.jpg\", signUrl: true)\n         \n        let expectedResult = \"https://res.cloudinary.com/test123/image/upload/s--2hbrSMPOjj5BJ4xV7SgFbRDevFaQNUFf--/sample.jpg\"\n        \n        // When\n        let actualResult = url!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for longUrlSignature = true and signUrl = true, should create a url with SHA256 encrypted apiSecret\")\n    }\n\n    // MARK: - signature algorithm\n    func test_signatureAlgorithm_emptyApiSecret_shouldCreateExpectedSigning() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"\", privateCdn: true, signatureAlgorithm: .sha256)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"DUB-5kBq\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 8, \"encrypted component should not be longer than 8 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and call for signUrl = true, should ecrypte with SHA256_base64\")\n    }\n    func test_signatureAlgorithm_normalApiSecret_shouldCreateExpectedSigning() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"apiSecret\", privateCdn: true, signatureAlgorithm: .sha256)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"UHH8qJ2e\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 8, \"encrypted component should not be longer than 8 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and call for signUrl = true, should ecrypte with SHA256_base64\")\n    }\n    func test_signatureAlgorithm_longApiSecret_shouldCreateExpectedSigning() {\n        \n        // Given\n        let longString = \"abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz2abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz4abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz6\"\n        let config = CLDConfiguration(cloudName: \"test123\", apiSecret: longString, privateCdn: true, signatureAlgorithm: .sha256)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"7k8KYHY2\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 8, \"encrypted component should not be longer than 8 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and call for signUrl = true, should ecrypte with SHA256_base64\")\n    }\n    func test_signatureAlgorithm_specialApiSecret_shouldCreateExpectedSigning() {\n        \n        // Given\n        let longString = \"🔭!@#$%^&*()_+±§?><`~\"\n        let config = CLDConfiguration(cloudName: \"test123\", apiSecret: longString, privateCdn: true, signatureAlgorithm: .sha256)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"g12ptQdG\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 8, \"encrypted component should not be longer than 8 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and call for signUrl = true, should ecrypte with SHA256_base64\")\n    }\n    func test_signatureAlgorithm_unset_shouldCreateExpectedSigning() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"apiSecret\", privateCdn: true)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"FhXe8ZZ3\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 8, \"encrypted component should not be longer than 8 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration without signatureAlgorithm and call for signUrl = true, should ecrypte with the default SHA1_base64\")\n    }\n    func test_signatureAlgorithm_signUrlFalse_shouldCreateFullUrlWithoutSigning() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"apiSecret\", privateCdn: true, signatureAlgorithm: .sha256, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: false)\n         \n        let expectedResult = \"http://test123-res.cloudinary.com/image/upload/test.jpg\"\n        \n        // When\n        let actualResult = url!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and call for signUrl = false, should not encrypt nor add the ApiSecret to the url\")\n    }\n    func test_signatureAlgorithm_unset_shouldCreateExpectedFullUrl() {\n        \n        // Given\n        let url = sut?.createUrl().generate(\"sample.jpg\", signUrl: true)\n         \n        let expectedResult = \"https://res.cloudinary.com/test123/image/upload/s--v2fTPYTu--/sample.jpg\"\n        \n        // When\n        let actualResult = url!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for default signatureAlgorithm and signUrl = true, should create a url with SHA1 encrypted apiSecret\")\n    }\n    func test_signatureAlgorithm_sha256_shouldCreateExpectedFullUrl() {\n        \n        // Given\n        let signatureAlgorithmQuery = (\"?analytics=false&\\(CLDConfiguration.ConfigParam.SignatureAlgorithm.description)=sha256\")\n        let urlCredentials          = \"cloudinary://a:b@test123\"\n        let fullUrl                 = urlCredentials + signatureAlgorithmQuery\n        \n        let config = CLDConfiguration(cloudinaryUrl: fullUrl)\n        sut = CLDCloudinary(configuration: config!)\n        let url = sut?.createUrl().generate(\"sample.jpg\", signUrl: true)\n         \n        let expectedResult = \"https://res.cloudinary.com/test123/image/upload/s--2hbrSMPO--/sample.jpg\"\n        \n        // When\n        let actualResult = url!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and signUrl = true, should create a url with SHA256 encrypted apiSecret\")\n    }\n    \n    // MARK: - signing combinations\n    func test_signingCombinations_signTrueLongTrueAlgorithmSha1_shouldUse32CharsEcryptedSha256() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"apiSecret\", privateCdn: true, longUrlSignature: true, signatureAlgorithm: .sha1)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"UHH8qJ2eIEoPHdVQP08BMEN9f4YUDavr\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 32, \"encrypted component should not be longer than 32 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"longUrlSignature should override signing algorithm and force sha256 with 32 charecters\")\n    }\n    func test_signingCombinations_signTrueLongTrueAlgorithmSha256_shouldUse32CharsEcryptedSha256() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"apiSecret\", privateCdn: true, longUrlSignature: true, signatureAlgorithm: .sha1)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: true)\n         \n        let expectedResult = \"UHH8qJ2eIEoPHdVQP08BMEN9f4YUDavr\"\n        \n        // When\n        let actualResult = url!.components(separatedBy: \"--\")[1]\n        \n        // Then\n        XCTAssertNotNil(actualResult, \"encrypted component should not be nil\")\n        XCTAssertTrue(actualResult.count <= 32, \"encrypted component should not be longer than 32 charecters\")\n        XCTAssertEqual(actualResult, expectedResult, \"longUrlSignature should override signing algorithm and force sha256 with 32 charecters\")\n    }\n    func test_signingCombinations_signFalseLongTrueAlgorithmSha1_shouldNotUseSigning() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"apiSecret\", privateCdn: true, longUrlSignature: true, signatureAlgorithm: .sha1, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: false)\n         \n        let expectedResult = \"http://test123-res.cloudinary.com/image/upload/test.jpg\"\n        \n        // When\n        let actualResult = url!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and longUrlSignature = true and call for signUrl = false, should not encrypt nor add the ApiSecret to the url\")\n    }\n    func test_signingCombinations_signFalseLongTrueAlgorithmSha256_shouldUseSigning() {\n        \n        // Given\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"apiKey\", apiSecret: \"apiSecret\", privateCdn: true, longUrlSignature: true, signatureAlgorithm: .sha256, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        let url = sut?.createUrl().setFormat(\"jpg\").generate(\"test\", signUrl: false)\n         \n        let expectedResult = \"http://test123-res.cloudinary.com/image/upload/test.jpg\"\n        \n        // When\n        let actualResult = url!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Setting the configuration for signatureAlgorithm to sha256 and longUrlSignature = true and call for signUrl = false, should not encrypt nor add the ApiSecret to the url\")\n    }\n    \n    // MARK: - root path\n    func testUseRootPathShared() {\n        XCTAssertEqual(sut?.createUrl().setUseRootPath(true).generate(\"test\"), \"\\(prefix)/test\")\n        XCTAssertEqual(sut?.createUrl().setUseRootPath(true).setTransformation(CLDTransformation().setAngle(0)).generate(\"test\"), \"\\(prefix)/a_0/test\")\n    }\n\n    func testUseRootPathNonImageUpload() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true)\n        sut = CLDCloudinary(configuration: config)\n        XCTAssertNil(sut?.createUrl().setUseRootPath(true).setType(.facebook).generate(\"test\"))\n        XCTAssertNil(sut?.createUrl().setUseRootPath(true).setResourceType(.raw).generate(\"test\"))\n    }\n\n    func testUseRootPathPrivateCdn() {\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        XCTAssertEqual(sut?.createUrl().setUseRootPath(true).generate(\"test\"), \"http://test123-res.cloudinary.com/test\")\n        XCTAssertEqual(sut?.createUrl().setUseRootPath(true).setTransformation(CLDTransformation().setAngle(0)).generate(\"test\"), \"http://test123-res.cloudinary.com/a_0/test\")\n    }\n\n    func testUseRootPathUrlSuffixPrivateCdn() {\n\n        let config = CLDConfiguration(cloudName: \"test123\", apiKey: \"a\", apiSecret: \"b\", privateCdn: true, analytics: false)\n        sut = CLDCloudinary(configuration: config)\n        XCTAssertEqual(sut?.createUrl().setUseRootPath(true).setSuffix(\"hello\").generate(\"test\"), \"http://test123-res.cloudinary.com/test/hello\")\n    }\n\n    func testHttpEscape() {\n\n        XCTAssertEqual(sut?.createUrl().setType(\"youtube\").generate(\"http://www.youtube.com/watch?v=d9NF2edxy-M\"), \"\\(prefix)/image/youtube/http://www.youtube.com/watch%3Fv%3Dd9NF2edxy-M\")\n    }\n\n    func testDoubleSlash() {\n\n        XCTAssertEqual(sut?.createUrl().setType(\"youtube\").generate(\"http://cloudinary.com//images//logo.png\"), \"\\(prefix)/image/youtube/http://cloudinary.com/images/logo.png\")\n    }\n\n    func testBackground() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setBackground(\"red\")).generate(\"test\"), \"\\(prefix)/image/upload/b_red/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setBackground(\"#112233\")).generate(\"test\"), \"\\(prefix)/image/upload/b_rgb:112233/test\")\n    }\n\n    func testKeyframeInterval() {\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setKeyframeInterval(interval: 10)).generate(\"test\"), \"\\(prefix)/image/upload/ki_10.0/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setKeyframeInterval(interval: 0.05)).generate(\"test\"), \"\\(prefix)/image/upload/ki_0.05/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setKeyframeInterval(interval: 3.45)).generate(\"test\"), \"\\(prefix)/image/upload/ki_3.45/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setKeyframeInterval(interval: 300)).generate(\"test\"), \"\\(prefix)/image/upload/ki_300.0/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setKeyframeInterval(\"10\")).generate(\"test\"), \"\\(prefix)/image/upload/ki_10/test\")\n    }\n\n    func testDefaultImage() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setDefaultImage(\"default\")).generate(\"test\"), \"\\(prefix)/image/upload/d_default/test\")\n    }\n\n    func testAngle() {\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setAngle(12)).generate(\"test\"), \"\\(prefix)/image/upload/a_12/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setAngle([\"exif\", \"12\"])).generate(\"test\"), \"\\(prefix)/image/upload/a_exif.12/test\")\n    }\n\n    func testOverlay() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlay(\"text:hello\")).generate(\"test\"), \"\\(prefix)/image/upload/l_text:hello/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlay(\"text:hello\").setWidth(100).setHeight(100)).generate(\"test\"), \"\\(prefix)/image/upload/h_100,l_text:hello,w_100/test\")\n    }\n\n    func testUnderlay() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setUnderlay(\"text:hello\")).generate(\"test\"), \"\\(prefix)/image/upload/u_text:hello/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setUnderlay(\"text:hello\").setWidth(100).setHeight(100)).generate(\"test\"), \"\\(prefix)/image/upload/h_100,u_text:hello,w_100/test\")\n    }\n\n    func testFetchFormat() {\n\n        XCTAssertEqual(sut?.createUrl().setType(.fetch).setFormat(\"jpg\").generate(\"http://cloudinary.com/images/logo.png\"), \"\\(prefix)/image/fetch/f_jpg/http://cloudinary.com/images/logo.png\")\n    }\n\n    func testEffect() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.sepia)).generate(\"test\"), \"\\(prefix)/image/upload/e_sepia/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.hue)).generate(\"test\"), \"\\(prefix)/image/upload/e_hue/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.red)).generate(\"test\"), \"\\(prefix)/image/upload/e_red/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.green)).generate(\"test\"), \"\\(prefix)/image/upload/e_green/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.blue)).generate(\"test\"), \"\\(prefix)/image/upload/e_blue/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.negate)).generate(\"test\"), \"\\(prefix)/image/upload/e_negate/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.brightness)).generate(\"test\"), \"\\(prefix)/image/upload/e_brightness/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.sepia)).generate(\"test\"), \"\\(prefix)/image/upload/e_sepia/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.grayscale)).generate(\"test\"), \"\\(prefix)/image/upload/e_grayscale/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.blackwhite)).generate(\"test\"), \"\\(prefix)/image/upload/e_blackwhite/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.saturation)).generate(\"test\"), \"\\(prefix)/image/upload/e_saturation/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.colorize)).generate(\"test\"), \"\\(prefix)/image/upload/e_colorize/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.contrast)).generate(\"test\"), \"\\(prefix)/image/upload/e_contrast/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.autoContrast)).generate(\"test\"), \"\\(prefix)/image/upload/e_auto_contrast/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.vibrance)).generate(\"test\"), \"\\(prefix)/image/upload/e_vibrance/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.autoColor)).generate(\"test\"), \"\\(prefix)/image/upload/e_auto_color/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.improve)).generate(\"test\"), \"\\(prefix)/image/upload/e_improve/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.autoBrightness)).generate(\"test\"), \"\\(prefix)/image/upload/e_auto_brightness/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.fillLight)).generate(\"test\"), \"\\(prefix)/image/upload/e_fill_light/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.viesusCorrect)).generate(\"test\"), \"\\(prefix)/image/upload/e_viesus_correct/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.gamma)).generate(\"test\"), \"\\(prefix)/image/upload/e_gamma/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.screen)).generate(\"test\"), \"\\(prefix)/image/upload/e_screen/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.multiply)).generate(\"test\"), \"\\(prefix)/image/upload/e_multiply/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.overlay)).generate(\"test\"), \"\\(prefix)/image/upload/e_overlay/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.makeTransparent)).generate(\"test\"), \"\\(prefix)/image/upload/e_make_transparent/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.trim)).generate(\"test\"), \"\\(prefix)/image/upload/e_trim/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.shadow)).generate(\"test\"), \"\\(prefix)/image/upload/e_shadow/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.distort)).generate(\"test\"), \"\\(prefix)/image/upload/e_distort/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.shear)).generate(\"test\"), \"\\(prefix)/image/upload/e_shear/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.displace)).generate(\"test\"), \"\\(prefix)/image/upload/e_displace/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.oilPaint)).generate(\"test\"), \"\\(prefix)/image/upload/e_oil_paint/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.redeye)).generate(\"test\"), \"\\(prefix)/image/upload/e_redeye/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.advRedeye)).generate(\"test\"), \"\\(prefix)/image/upload/e_adv_redeye/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.vignette)).generate(\"test\"), \"\\(prefix)/image/upload/e_vignette/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.gradientFade)).generate(\"test\"), \"\\(prefix)/image/upload/e_gradient_fade/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.pixelate)).generate(\"test\"), \"\\(prefix)/image/upload/e_pixelate/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.pixelateRegion)).generate(\"test\"), \"\\(prefix)/image/upload/e_pixelate_region/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.pixelateFaces)).generate(\"test\"), \"\\(prefix)/image/upload/e_pixelate_faces/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.blur)).generate(\"test\"), \"\\(prefix)/image/upload/e_blur/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.blurRegion)).generate(\"test\"), \"\\(prefix)/image/upload/e_blur_region/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.blurFaces)).generate(\"test\"), \"\\(prefix)/image/upload/e_blur_faces/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.sharpen)).generate(\"test\"), \"\\(prefix)/image/upload/e_sharpen/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.unsharpMask)).generate(\"test\"), \"\\(prefix)/image/upload/e_unsharp_mask/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.orderedDither)).generate(\"test\"), \"\\(prefix)/image/upload/e_ordered_dither/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.art)).generate(\"test\"), \"\\(prefix)/image/upload/e_art/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.assistColorblind)).generate(\"test\"), \"\\(prefix)/image/upload/e_assist_colorblind/test\")\n        XCTAssertEqual(sut?.createUrl().setResourceType(.video).setTransformation(CLDTransformation().setEffect(.preview)).generate(\"test\"), \"\\(prefix)/video/upload/e_preview/test\")\n        XCTAssertEqual(sut?.createUrl().setResourceType(.video).setTransformation(CLDTransformation().setEffect(.preview, param: \"duration_2\")).generate(\"test\"), \"\\(prefix)/video/upload/e_preview:duration_2/test\")\n    }\n\n    func testEffectWithParam() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.sepia, param: \"10\")).generate(\"test\"), \"\\(prefix)/image/upload/e_sepia:10/test\")\n    }\n    \n    func testArtisticEffect(){\n        \n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.alDente)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:al_dente/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.athena)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:athena/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.audrey)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:audrey/test\")\n        \n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.aurora)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:aurora/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.daguerre)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:daguerre/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.eucalyptus)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:eucalyptus/test\")\n        \n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.fes)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:fes/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.frost)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:frost/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.hairspray)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:hairspray/test\")\n        \n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.hokusai)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:hokusai/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.incognito)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:incognito/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.linen)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:linen/test\")\n        \n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.peacock)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:peacock/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.primavera)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:primavera/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.quartz)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:quartz/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.redRock)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:red_rock/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.refresh)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:refresh/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.sizzle)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:sizzle/test\")\n        \n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.sonnet)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:sonnet/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.ukulele)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:ukulele/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setEffect(.zorro)).generate(\"test\"), \"\\(prefix)/image/upload/e_art:zorro/test\")\n    }\n\n    func testDensity() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setDensity(150)).generate(\"test\"), \"\\(prefix)/image/upload/dn_150/test\")\n    }\n\n    func testPage() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setPage(5)).generate(\"test\"), \"\\(prefix)/image/upload/pg_5/test\")\n    }\n\n    func testBorder() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setBorder(5, color: \"black\")).generate(\"test\"), \"\\(prefix)/image/upload/bo_5px_solid_black/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setBorder(5, color: \"#ffaabbdd\")).generate(\"test\"), \"\\(prefix)/image/upload/bo_5px_solid_rgb:ffaabbdd/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setBorder(\"1px_solid_blue\")).generate(\"test\"), \"\\(prefix)/image/upload/bo_1px_solid_blue/test\")\n    }\n\n    func testFlags() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setFlags([\"abc\"])).generate(\"test\"), \"\\(prefix)/image/upload/fl_abc/test\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setFlags([\"abc\", \"def\"])).generate(\"test\"), \"\\(prefix)/image/upload/fl_abc.def/test\")\n    }\n\n    func testDprFloat() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setDpr(2.0)).generate(\"test\"), \"\\(prefix)/image/upload/dpr_2.0/test\")\n    }\n\n    func testDprAuto() {\n        let url = sut?.createUrl().setTransformation(CLDTransformation().setDprAuto()).generate(\"test\")\n        var dprValue = \"\"\n        if let finalUrl = url, let range = finalUrl.range(of: \"dpr_\") {\n            let startIndex = range.upperBound\n            dprValue = String(finalUrl[startIndex..<(finalUrl.index(startIndex, offsetBy: 1))])\n        }\n\n        if !dprValue.isEmpty {\n            XCTAssert(Int(dprValue) != nil, \"DPR value should be transformed to Int value\")\n        } else {\n            XCTFail(\"should find DPR Value\")\n        }\n    }\n\n    func testAspectRatio() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setAspectRatio(2.0)).generate(\"test\"), \"\\(prefix)/image/upload/ar_2.0/test\")\n    }\n\n    func testSignature() {\n        let sig = cloudinarySignParamsUsingSecret([\"a\": \"b\", \"c\": \"d\", \"e\": \"\"], cloudinaryApiSecret: \"abcd\")\n        XCTAssertEqual(sig, \"ef1f04e0c1af08208a3dd28483107bc7f4a61209\")\n    }\n\n    func testFolders() {\n\n        XCTAssertEqual(sut?.createUrl().generate(\"folder/test\"), \"\\(prefix)/image/upload/v1/folder/test\")\n        XCTAssertEqual(sut?.createUrl().setVersion(\"123\").generate(\"folder/test\"), \"\\(prefix)/image/upload/v123/folder/test\")\n    }\n    \n    func testFoldersWithForceVersion(){\n        // should not add version if the user turned off forceVersion\n        var result = sut?.createUrl().setForceVersion(false).generate(\"folder/test\")\n        XCTAssertEqual(\"\\(prefix)/image/upload/folder/test\", result)\n        \n        // should still show explicit version if passed by the user\n        result = sut?.createUrl().setForceVersion(false).setVersion(\"1234\").generate(\"folder/test\")\n        XCTAssertEqual(\"\\(prefix)/image/upload/v1234/folder/test\", result)\n        \n        // should add version if no value specified for forceVersion:\n        result = sut?.createUrl().generate(\"folder/test\")\n        XCTAssertEqual(\"\\(prefix)/image/upload/v1/folder/test\", result)\n        \n        // should add version if forceVersion is true\n        result = sut?.createUrl().setForceVersion(true).generate(\"folder/test\");\n        XCTAssertEqual(\"\\(prefix)/image/upload/v1/folder/test\", result)\n        \n        // should not use v1 if explicit version is passed\n        result = sut?.createUrl().setForceVersion(true).setVersion(\"1234\").generate(\"folder/test\");\n        XCTAssertEqual(\"\\(prefix)/image/upload/v1234/folder/test\", result)\n    }\n\n    func testFoldersWithVersion() {\n\n        XCTAssertEqual(sut?.createUrl().generate(\"v1234/test\"), \"\\(prefix)/image/upload/v1234/test\")\n    }\n\n    func testShorten() {\n\n        XCTAssertEqual(sut?.createUrl().setShortenUrl(true).generate(\"test\"), \"\\(prefix)/iu/test\")\n    }\n\n    func testSignUrls() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setWidth(10).setHeight(20).setCrop(.crop)).setVersion(\"1234\").generate(\"image.jpg\", signUrl: true), \"\\(prefix)/image/upload/s--Ai4Znfl3--/c_crop,h_20,w_10/v1234/image.jpg\")\n    }\n\n    func testEscapePublicId() {\n\n        let tests = [\"a b\": \"a%20b\", \"a+b\": \"a%2Bb\", \"a%20b\": \"a%20b\", \"a-b\": \"a-b\", \"a??b\": \"a%3F%3Fb\"]\n        for key in tests.keys {\n            XCTAssertEqual(sut?.createUrl().generate(key), \"\\(prefix)/image/upload/\\(tests[key]!)\")\n        }\n    }\n\n    func testPreloadedImage() {\n\n        XCTAssertEqual(sut?.createUrl().generate(\"raw/private/v1234567/document.docx\"), \"\\(prefix)/raw/private/v1234567/document.docx\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setWidth(1.1).setCrop(.scale)).generate(\"image/private/v1234567/img.jpg\"), \"\\(prefix)/image/private/c_scale,w_1.1/v1234567/img.jpg\")\n    }\n\n    func testGravity() {\n        testGravityUrl(CLDTransformation.CLDGravity.center, \"c_crop,g_center,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.auto, \"c_crop,g_auto,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.face, \"c_crop,g_face,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.faceCenter, \"c_crop,g_face:center,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.faces, \"c_crop,g_faces,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.facesCenter, \"c_crop,g_faces:center,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.advFace, \"c_crop,g_adv_face,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.advFaces, \"c_crop,g_adv_faces,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.advEyes, \"c_crop,g_adv_eyes,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.north, \"c_crop,g_north,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.northWest, \"c_crop,g_north_west,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.northEast, \"c_crop,g_north_east,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.south, \"c_crop,g_south,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.southWest, \"c_crop,g_south_west,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.southEast, \"c_crop,g_south_east,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.west, \"c_crop,g_west,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.east, \"c_crop,g_east,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.xyCenter, \"c_crop,g_xy_center,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.custom, \"c_crop,g_custom,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.customFace, \"c_crop,g_custom:face,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.customFaces, \"c_crop,g_custom:faces,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.customAdvFace, \"c_crop,g_custom:adv_face,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.customAdvFaces, \"c_crop,g_custom:adv_faces,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.autoOcrText, \"c_crop,g_auto:ocr_text,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.ocrText, \"c_crop,g_ocr_text,w_100\")\n        testGravityUrl(CLDTransformation.CLDGravity.ocrTextAdvOcr, \"c_crop,g_ocr_text:adv_ocr,w_100\")\n    }\n\n    fileprivate func testGravityUrl(_ gravity: CLDTransformation.CLDGravity, _ expected: String) {\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setWidth(100).setCrop(CLDTransformation.CLDCrop.crop).setGravity(gravity)).generate(\"public_id\"),\n                \"\\(prefix)/image/upload/\\(expected)/public_id\",\"Creating url with gravity enum should return expected result\")\n    }\n\n    func testVideoCodec() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVideoCodec(\"auto\")).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/vc_auto/video_id\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVideoCodecAndProfileAndLevel(\"h264\", videoProfile: \"basic\", level: \"3.1\")).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/vc_h264:basic:3.1/video_id\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVideoCodecAndProfileAndLevel(\"h264\", videoProfile: \"basic\", level: nil)).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/vc_h264:basic/video_id\")\n    }\n\n    func testVideoCodecBFrameTrueOrNil() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVideoCodecAndProfileAndLevelAndBFrames(\"h264\", videoProfile: \"basic\", level: \"3.1\", bframes: true)).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/vc_h264:basic:3.1/video_id\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVideoCodecAndProfileAndLevelAndBFrames(\"h264\", videoProfile: \"basic\", level: \"3.1\", bframes: nil)).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/vc_h264:basic:3.1/video_id\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVideoCodecAndProfileAndLevelAndBFrames(\"h264\", videoProfile: \"basic\", level: \"3.1\")).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/vc_h264:basic:3.1/video_id\")\n    }\n\n    func testVideoCodecBFrameFalse() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVideoCodecAndProfileAndLevelAndBFrames(\"h264\", videoProfile: \"basic\", level: \"3.1\", bframes: false)).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/vc_h264:basic:3.1:bframes_no/video_id\")\n    }\n\n    func testAudioCodec() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setAudioCodec(\"acc\")).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/ac_acc/video_id\")\n    }\n\n    func testBitRate() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setBitRate(\"1m\")).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/br_1m/video_id\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setBitRate(2048)).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/br_2048/video_id\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setBitRate(kb: 44)).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/br_44k/video_id\")\n    }\n\n    func testAudioFrequency() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setAudioFrequency(\"44100\")).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/af_44100/video_id\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setAudioFrequency(44100)).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/af_44100/video_id\")\n    }\n\n    func testVideoSampling() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVideoSampling(\"20\")).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/vs_20/video_id\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVideoSampling(frames: 20)).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/vs_20/video_id\")\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setVideoSampling(delay: 2.3)).setResourceType(.video).generate(\"video_id\"), \"\\(prefix)/video/upload/vs_2.3s/video_id\")\n    }\n\n    func testOverlayOptions() {\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDLayer().setPublicId(publicId: \"logo\"))).generate(\"test\"), \"\\(prefix)/image/upload/l_logo/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDLayer().setPublicId(publicId: \"logo\").setType(.private))).generate(\"test\"), \"\\(prefix)/image/upload/l_private:logo/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDLayer().setPublicId(publicId: \"logo\").setFormat(format: \"png\"))).generate(\"test\"), \"\\(prefix)/image/upload/l_logo.png/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDLayer().setPublicId(publicId: \"folder/logo\"))).generate(\"test\"), \"\\(prefix)/image/upload/l_folder:logo/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDLayer().setPublicId(publicId: \"cat\").setResourceType(.video))).generate(\"test\"), \"\\(prefix)/image/upload/l_video:cat/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDTextLayer().setText(text: \"Hello/World\").setFontFamily(fontFamily: \"Arial\").setFontSize(18))).generate(\"test\"), \"\\(prefix)/image/upload/l_text:Arial_18:Hello%252FWorld/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDTextLayer().setText(text: \"Hello World, Nice to meet you?\").setFontFamily(fontFamily: \"Arial\").setFontSize(18))).generate(\"test\"), \"\\(prefix)/image/upload/l_text:Arial_18:Hello%20World%252C%20Nice%20to%20meet%20you%3F/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDTextLayer().setText(text: \"Hello World, Nice to meet you?\").setFontFamily(fontFamily: \"Arial\").setFontSize(18).setFontStyle(.italic).setFontWeight(.bold).setLetterSpacing(4))).generate(\"test\"), \"\\(prefix)/image/upload/l_text:Arial_18_bold_italic_letter_spacing_4:Hello%20World%252C%20Nice%20to%20meet%20you%3F/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDSubtitlesLayer().setPublicId(publicId: \"sample_sub_en.srt\"))).generate(\"test\"), \"\\(prefix)/image/upload/l_subtitles:sample_sub_en.srt/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDSubtitlesLayer().setFontFamily(fontFamily: \"Arial\").setFontSize(40).setPublicId(publicId: \"sample_sub_he.srt\"))).generate(\"test\"), \"\\(prefix)/image/upload/l_subtitles:Arial_40:sample_sub_he.srt/test\")\n        \n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDSubtitlesLayer().setFontFamily(fontFamily:\"Arial\").setFontSize(40).setFontAntialiasing(CLDTextLayer.CLDFontAntialiasing.FAST)\n            .setFontHinting(CLDTextLayer.CLDFontHinting.MEDIUM).setPublicId(publicId: \"sample_sub_he.srt\"))).generate(\"test\"), \"\\(prefix)/image/upload/l_subtitles:Arial_40_antialias_fast_hinting_medium:sample_sub_he.srt/test\")\n\n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDSubtitlesLayer().setFontFamily(fontFamily:\"Arial\").setFontSize(40).setFontAntialiasing(\"fast\")\n            .setFontHinting(\"medium\").setPublicId(publicId: \"sample_sub_he.srt\"))).generate(\"test\"), \"\\(prefix)/image/upload/l_subtitles:Arial_40_antialias_fast_hinting_medium:sample_sub_he.srt/test\")\n        \n        XCTAssertEqual(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDFetchLayer(url: \"https://res.cloudinary.com/demo/image/upload/sample\"))).generate(\"test\"),\n                       \"\\(prefix)/image/upload/l_fetch:aHR0cHM6Ly9yZXMuY2xvdWRpbmFyeS5jb20vZGVtby9pbWFnZS91cGxvYWQvc2FtcGxl/test\")\n    }\n\n    func testOverlayErrors() {\n        XCTAssertNil(sut?.createUrl().setTransformation(CLDTransformation().setOverlayWithLayer(CLDTextLayer().setText(text: \"text\").setFontStyle(.italic))).generate(\"test\"))\n\n        XCTAssertNil(sut?.createUrl().setTransformation(CLDTransformation().setUnderlayWithLayer(CLDLayer().setResourceType(.video))).generate(\"test\"))\n    }\n    // MARK: - fsp\n    func testFps(){\n        XCTAssertEqual(CLDTransformation().setFps(\"24-29.97\").asString() ,\"fps_24-29.97\")\n        XCTAssertEqual(CLDTransformation().setFps(24).asString() ,\"fps_24\")\n        XCTAssertEqual(CLDTransformation().setFps(24.5).asString() ,\"fps_24.5\")\n        XCTAssertEqual(CLDTransformation().setFps(\"24\").asString() ,\"fps_24\")\n        XCTAssertEqual(CLDTransformation().setFps(\"-24\").asString() ,\"fps_-24\")\n        XCTAssertEqual(CLDTransformation().setFps(.range (start: 24, end: 29.97)).asString() ,\"fps_24-29.97\")\n        XCTAssertEqual(CLDTransformation().setFps(.range (start: \"24\", end: \"29.97\")).asString() ,\"fps_24-29.97\")\n        XCTAssertEqual(CLDTransformation().setFps(.range (start: 24)).asString() ,\"fps_24-\")\n        XCTAssertEqual(CLDTransformation().setFps(.range (end: 29.97)).asString() ,\"fps_-29.97\")\n        XCTAssertEqual(CLDTransformation().setFps(.range (start: \"24\")).asString() ,\"fps_24-\")\n        XCTAssertEqual(CLDTransformation().setFps(.range (end: \"29.97\")).asString() ,\"fps_-29.97\")\n    }\n    \n    func testEagerWithStreamingProfile(){\n        XCTAssertEqual(CLDEagerTransformation().setFormat(\"m3u8\").setStreamingProfile(\"full_hd\").asString(), \"sp_full_hd/m3u8\")\n    }\n    \n    func testInitialHeightWidth() {\n        XCTAssertEqual(CLDTransformation().setWidth(\"iw\").setHeight(\"ih\").setCrop(.crop).asString() ,\"c_crop,h_ih,w_iw\")\n    }\n    \n    func testOffset(){\n        XCTAssertEqual(CLDTransformation().setStartOffset(\"auto\").asString(), \"so_auto\")\n    }\n    \n    // MARK: - named spaces removal\n    func test_replaceSpaces_named_shouldCreateExpectedUrl() {\n        \n        // Given\n        let input = \"name\"\n        \n        let expectedResult = \"https://res.cloudinary.com/test123/image/upload/h_101,t_name,w_100/test\"\n        \n        // When\n        let transformation = CLDTransformation().setWidth(100).setHeight(101).setNamed(input)\n        let actualResult   = sut?.createUrl().setTransformation(transformation).generate(\"test\")\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"creating url with named in transformation should return the expected result\")\n    }\n    func test_replaceSpaces_namedWithSpaces_shouldReplaceSpaces() {\n        \n        // Given\n        let input = \"name with spaces\"\n        \n        let expectedResult = \"https://res.cloudinary.com/test123/image/upload/h_101,t_name%20with%20spaces,w_100/test\"\n        \n        // When\n        let transformation = CLDTransformation().setWidth(100).setHeight(101).setNamed(input)\n        let actualResult   = sut?.createUrl().setTransformation(transformation).generate(\"test\")\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"creating url with named in transformation should return the expected result\")\n    }\n    func test_replaceSpaces_namedArray_shouldCreateExpectedUrl() {\n        \n        // Given\n        let input1 = \"name1\"\n        let input2 = \"name2\"\n        \n        let expectedResult = \"https://res.cloudinary.com/test123/image/upload/h_101,t_name1.name2,w_100/test\"\n        \n        // When\n        let transformation = CLDTransformation().setWidth(100).setHeight(101).setNamed([input1, input2])\n        let actualResult   = sut?.createUrl().setTransformation(transformation).generate(\"test\")\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"creating url with named in transformation should return the expected result\")\n    }\n    func test_replaceSpaces_namedArrayWithSpaces_shouldReplaceSpaces() {\n        \n        // Given\n        let input1 = \"named with spaces 1\"\n        let input2 = \"named with spaces 2\"\n        \n        let expectedResult = \"https://res.cloudinary.com/test123/image/upload/h_101,t_named%20with%20spaces%201.named%20with%20spaces%202,w_100/test\"\n        \n        // When\n        let transformation = CLDTransformation().setWidth(100).setHeight(101).setNamed([input1, input2])\n        let actualResult   = sut?.createUrl().setTransformation(transformation).generate(\"test\")\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"creating url with named in transformation should return the expected result\")\n    }\n}\n\n\n"
  },
  {
    "path": "Example/Tests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>cldCloudinaryUrl</key>\n\t<string>$(CLOUDINARY_URL)</string>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>UIApplicationSceneManifest</key>\n\t<dict>\n\t\t<key>UIApplicationSupportsMultipleScenes</key>\n\t\t<false/>\n\t\t<key>UISceneConfigurations</key>\n\t\t<dict>\n\t\t\t<key>UIWindowSceneSessionRoleApplication</key>\n\t\t\t<array>\n\t\t\t\t<dict>\n\t\t\t\t\t<key>UISceneConfigurationName</key>\n\t\t\t\t\t<string>Default Configuration</string>\n\t\t\t\t\t<key>UISceneDelegateClassName</key>\n\t\t\t\t\t<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>\n\t\t\t\t\t<key>UISceneStoryboardFile</key>\n\t\t\t\t\t<string>Splash</string>\n\t\t\t\t</dict>\n\t\t\t</array>\n\t\t</dict>\n\t</dict>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~iphone</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UIApplicationSupportsIndirectInputEvents</key>\n\t<true/>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "Example/Tests/NetworkTests/AccessibilityUploderTests/UploaderAccessibilityTests.m",
    "content": "//\n//  UploaderAccessibilityTests.m\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"Cloudinary_Tests-Swift.h\"\n#import \"NetworkBaseTestObjc.h\"\n\n@interface UploaderAccessibilityTests: NetworkBaseTestObjc\n@end\n\n@implementation UploaderAccessibilityTests\n\n// MARK: - upload result\n- (void)test_uploadResult_accessibiltyAnalysisUnset_shouldNotReturnAccessibilityInfo {\n\n    XCTAssertNotNil(self.cloudinary.config.apiSecret, \"Must set api secret for this test\");\n    \n    // Given\n    XCTestExpectation *expectation = [self expectationWithDescription:@\"upload should succeed\"];\n    \n    TestResourceType resource = borderCollie;\n    NSURL* file = [self getUrlBy:resource];\n    \n    __block CLDUploadResult* sut;\n    __block NSError* error;\n    \n    CLDUploadRequestParams* params = [[CLDUploadRequestParams alloc] init];\n    \n    // When\n    [[[self.cloudinary createUploader] signedUploadWithUrl:file params:params progress:nil completionHandler:nil] response:^(CLDUploadResult* resultRes, NSError* errorRes) {\n\n        sut   = resultRes;\n        error = errorRes;\n\n        [expectation fulfill];\n    }];\n    \n    [self waitForExpectationsWithTimeout:self.timeout handler:nil];\n    \n    // Then\n    XCTAssertNil(error, \"error should be nil\");\n    XCTAssertNotNil(sut, \"result should not be nil\");\n    XCTAssertNil(sut.accessibilityAnalysis, \"accessibility analysis field in upload result without setAccessibilityAnalysis(true) should be nil\");\n}\n- (void)test_uploadResult_accessibiltyAnalysisParsing_shouldParseAsExpected {\n\n    XCTAssertNotNil(self.cloudinary.config.apiSecret, \"must set api secret for this test\");\n    \n    // Given\n    XCTestExpectation *expectation = [self expectationWithDescription:@\"upload with accessibility should succeed\"];\n    \n    TestResourceType resource = borderCollie;\n    NSURL* file = [self getUrlBy:resource];\n    \n    __block CLDUploadResult* sut;\n    __block NSError* error;\n    \n    CLDUploadRequestParams* params = [[CLDUploadRequestParams alloc] init];\n    [params setAccessibilityAnalysis:YES];\n    \n    // When\n    [[[self.cloudinary createUploader] signedUploadWithUrl:file params:params progress:nil completionHandler:nil] response:^(CLDUploadResult* resultRes, NSError* errorRes) {\n\n        sut   = resultRes;\n        error = errorRes;\n\n        [expectation fulfill];\n    }];\n    \n    [self waitForExpectationsWithTimeout:self.timeout handler:nil];\n    \n    // Then\n    XCTAssertNil(error, \"error should be nil\");\n    XCTAssertNotNil(sut, \"result should not be nil\");\n    XCTAssertNotNil(sut.accessibilityAnalysis, \"accessibility analysis field in upload result should not be nil\");\n    \n    // accessability analysis\n    XCTAssertNotNil(sut.accessibilityAnalysis.colorblindAccessibilityAnalysis, \"accessibility analysis field in upload result should not be nil\");\n    XCTAssertNotNil(sut.accessibilityAnalysis.colorblindAccessibilityAnalysis.mostIndistinctPair\n                    , \"accessibility analysis field in upload result should not be nil\");\n    XCTAssertNotNil(sut.accessibilityAnalysis.colorblindAccessibilityAnalysis.mostIndistinctPair[0]\n                    , \"accessibility analysis field in upload result should not be nil\");\n}\n\n// MARK: - explicit\n- (void)test_explicitResult_accessibiltyAnalysisParsing_shouldParseAsExpected {\n\n    XCTAssertNotNil(self.cloudinary.config.apiSecret, \"must set api secret for this test\");\n    \n    // Given\n    XCTestExpectation *expectation = [self expectationWithDescription:@\"upload should succeed\"];\n    \n    TestResourceType resource = borderCollie;\n    NSURL* file = [self getUrlBy:resource];\n    \n    __block CLDUploadResult* uploadResult;\n    __block NSError* error;\n    \n    CLDUploadRequestParams* params = [[CLDUploadRequestParams alloc] init];\n    [params setAccessibilityAnalysis:YES];\n    \n    // When\n    [[[self.cloudinary createUploader] signedUploadWithUrl:file params:params progress:nil completionHandler:nil] response:^(CLDUploadResult* resultRes, NSError* errorRes) {\n\n        uploadResult = resultRes;\n        error = errorRes;\n\n        [expectation fulfill];\n    }];\n    \n    [self waitForExpectationsWithTimeout:self.timeout handler:nil];\n    \n    // Then\n    XCTAssertNil(error, \"error should be nil\");\n    XCTAssertNotNil(uploadResult, \"result should not be nil\");\n}\n- (void) callForExplicitWithAccessibility:(NSString*) publicId {\n    \n    if(publicId == nil) {\n        return;\n    }\n    \n    // Given\n    XCTestExpectation *expectation =\n           [self expectationWithDescription:@\"explicit call with accessibility should succeed\"];\n    \n    __block CLDUploadResult* sut;\n    __block NSError* error;\n    \n    CLDExplicitRequestParams* params = [[CLDExplicitRequestParams alloc] init];\n    [params setAccessibilityAnalysis:YES];\n    \n    // When\n    [[[self.cloudinary createManagementApi] explicitPublicId:publicId stringType:@\"upload\" params:params completionHandler:nil] response:^(CLDExplicitResult* resultRes, NSError* errorRes) {\n        \n        sut   = resultRes;\n        error = errorRes;\n\n        [expectation fulfill];\n    }];\n    \n    [self waitForExpectationsWithTimeout:self.timeout handler:nil];\n    \n    // Then\n    XCTAssertNil(error, \"error should be nil\");\n    XCTAssertNotNil(sut, \"result should not be nil\");\n    XCTAssertNotNil(sut.accessibilityAnalysis, \"accessibility analysis field in upload result should not be nil\");\n    \n    // accessability analysis\n    XCTAssertNotNil(sut.accessibilityAnalysis.colorblindAccessibilityAnalysis, \"accessibility analysis field in upload result should not be nil\");\n    XCTAssertNotNil(sut.accessibilityAnalysis.colorblindAccessibilityAnalysis.mostIndistinctPair\n                    , \"accessibility analysis field in upload result should not be nil\");\n    XCTAssertNotNil(sut.accessibilityAnalysis.colorblindAccessibilityAnalysis.mostIndistinctPair[0]\n                    , \"accessibility analysis field in upload result should not be nil\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/NetworkTests/AccessibilityUploderTests/UploaderAccessibilityTests.swift",
    "content": "//\n//  UploaderAccessibilityTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\nclass UploaderAccessibilityTests: NetworkBaseTest {\n\n    // MARK: - upload\n    func test_uploadResult_accessibiltyAnalysisUnset_shouldNotReturnAccessibilityInfo() {\n       \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        \n        // Given\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        \n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var sut: CLDUploadResult?\n        var error: NSError?\n        \n        let params = CLDUploadRequestParams()\n        \n        // When\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            sut   = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(sut, \"result should not be nil\")\n        XCTAssertNil(sut?.accessibilityAnalysis, \"accessibility analysis field in upload result without setAccessibilityAnalysis(true) should be nil\")\n    }\n    func test_uploadResult_accessibiltyAnalysisParsing_shouldParseAsExpected() {\n       \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        \n        // Given\n        let expectation = self.expectation(description: \"Upload with accessibility should succeed\")\n        \n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var sut: CLDUploadResult?\n        var error: NSError?\n        \n        let params = CLDUploadRequestParams()\n        params.setAccessibilityAnalysis(true)\n        \n        // When\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            sut   = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(sut, \"result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis, \"accessibility analysis field in upload result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityScore, \"accessibility analysis field in upload result should not be nil\")\n        \n        // accessability analysis\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityAnalysis, \"accessibility analysis field in upload result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityAnalysis?.distinctColors, \"accessibility analysis field in upload result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityAnalysis?.distinctEdges, \"accessibility analysis field in upload result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityAnalysis?.mostIndistinctPair\n            , \"accessibility analysis field in upload result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityAnalysis?.mostIndistinctPair?[0]\n        , \"accessibility analysis field in upload result should not be nil\")\n    }\n    \n    // MARK: - explicit\n    func test_explicitResult_accessibiltyAnalysisParsing_shouldParseAsExpected() {\n       \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        \n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let params = CLDUploadRequestParams()\n        params.setAccessibilityAnalysis(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error  = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        callForExplicitWithAccessibility(publicId: result?.publicId)\n        \n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n    func callForExplicitWithAccessibility(publicId: String?) {\n\n        guard let publicId = publicId else { return }\n        \n        // Given\n        let expectation = self.expectation(description: \"Explicit call with accessibility should succeed\")\n        \n        var sut: CLDExplicitResult?\n        var error: NSError?\n        \n        // When\n        let params = CLDExplicitRequestParams()\n        params.setAccessibilityAnalysis(true)\n        cloudinary!.createManagementApi().explicit(publicId, type: \"upload\", params: params).response({ (resultRes, errorRes) in\n            sut   = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(sut, \"result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis, \"accessibility analysis field in upload result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityScore, \"accessibility analysis field in upload result should not be nil\")\n        \n        // accessability analysis\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityAnalysis, \"accessibility analysis field in upload result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityAnalysis?.distinctColors, \"accessibility analysis field in upload result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityAnalysis?.distinctEdges, \"accessibility analysis field in upload result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityAnalysis?.mostIndistinctPair\n            , \"accessibility analysis field in upload result should not be nil\")\n        XCTAssertNotNil(sut?.accessibilityAnalysis?.colorblindAccessibilityAnalysis?.mostIndistinctPair?[0]\n        , \"accessibility analysis field in upload result should not be nil\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/DownloaderAssetTests.swift",
    "content": "//\n//  DownloaderAssetTests.swift\n//\n//  Copyright (c) 2021 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\nimport Cloudinary\n@testable import Cloudinary\n\n// MARK: - assets\nclass DownloaderAssetTests: NetworkBaseTest {\n    \n    var sut: CLDDownloader!\n    \n    override func setUp() {\n        super.setUp()\n        \n        sut = cloudinary!.createDownloader()\n    }\n    \n    override func tearDown() {\n        \n        CLDDownloadCoordinator.urlCache.removeAllCachedResponses()\n        sut = nil\n        super.tearDown()\n    }\n    \n    static var skipableTests = [\n        (\"test_downloadAsset_pdfImage_shouldDownloadAndCacheAsset\", test_downloadAsset_pdfImage_shouldDownloadAndCacheAsset),\n    ]\n        \n    override func shouldSkipTest() -> Bool {\n        \n        if super.shouldSkipTest() {\n            return true\n        }\n        if ProcessInfo.processInfo.arguments.contains(\"TEST_PDF\") {\n            return false\n        }\n        if let privateName = testRun?.test.name {\n            if !DownloaderAssetTests.skipableTests.filter({\n                return privateName.contains($0.0)\n            }).isEmpty {\n                return true\n            }\n        }\n        return false\n    }\n    \n    // MARK - cache asset\n    func test_downloadAsset_video_shouldDownloadAndCacheAsset() {\n        assetCacheTest(shouldCache: true, testResource: .dog2, resourceType: .video)\n    }\n    func test_downloadAsset_pdfImage_shouldDownloadAndCacheAsset() {\n        assetCacheTest(shouldCache: true, testResource: .pdf, resourceType: .image)\n    }\n    func test_downloadAsset_pdfRaw_shouldDownloadAndCacheAsset() {\n        assetCacheTest(shouldCache: true, testResource: .pdf, resourceType: .raw)\n    }\n    func test_downloadAsset_docx_shouldDownloadAndCacheAsset() {\n        assetCacheTest(shouldCache: true, testResource: .docx, resourceType: .raw)\n    }\n    \n    // MARK - download without cache\n    func test_downloadAsset_image_shouldDownloadWithoutCaching() {\n        // images are excluded from asset cache use \"fetchImage\" instead of \"fetchAsset\".\n        assetCacheTest(shouldCache: false,testResource: .borderCollie, resourceType: .image)\n    }\n    func test_downloadAsset_video_shouldDownloadWithoutCaching() {\n        assetCacheTest(shouldCache: false, testResource: .dog2, resourceType: .video)\n    }\n}\n\nextension DownloaderAssetTests {\n    \n    func assetCacheTest(shouldCache: Bool, testResource: TestResourceType, resourceType: CLDUrlResourceType) {\n        \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        \n        // Given\n        let resource: TestResourceType = testResource\n        var publicId: String?\n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        let params = CLDUploadRequestParams()\n        params.setResourceType(resourceType)\n        \n        // When\n        uploadFile(resource, params: params).response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: longTimeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"Download should succeed\")\n        \n        var response: Data?\n        \n        /// download asset by publicId\n        let url = cloudinary!.createUrl().setResourceType(resourceType).generate(pubId)\n        let request = sut.fetchAsset(url!).responseAsset { (responseData, err) in\n            response = responseData\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertEqual(response, resource.data, \"uploaded data should be equal to downloaded data\")\n    }\n}\n\n// MARK - test status code\nextension DownloaderAssetTests {\n\n    func test_downloadAsset_unacceptableStatusCode_shouldReturnEmptyValueAndError() {\n        \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        \n        // Given\n        let resource: TestResourceType = .pdf\n        var publicId: String?\n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        let params = CLDUploadRequestParams()\n        params.setResourceType(.auto)\n        \n        // When\n        uploadFile(resource, params: params).response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: longTimeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"Download should succeed\")\n        \n        var response: Data?\n        var error   : NSError?\n        \n        /// download asset by publicId\n        let url = cloudinary!.createUrl().setResourceType(.auto).generate(pubId)\n        sut.fetchAsset(url!).responseAsset { (responseData, responseError) in\n            response = responseData\n            error = responseError\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        if let response = response {\n            XCTAssert(response.isEmpty, \"downloaded response should be empty\")\n        }\n        else {\n            XCTFail(\"downloaded response should be empty but valid\")\n        }\n\n        XCTAssertNotNil(error, \"downloaded error should indicate unacceptable status code\")\n        XCTAssertEqual (error?.code, CLDError.CloudinaryErrorCode.unacceptableStatusCode.rawValue, \"downloaded error status code should be 401\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/DownloaderTests.swift",
    "content": "//\n//  DownloaderTests.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\nimport Cloudinary\n@testable import Cloudinary\n\nclass DownloaderTests: NetworkBaseTest {\n\n    // MARK: - Tests\n    func test_downloadImage_shouldReturnNetworkErrorCode() {\n        var expectation = self.expectation(description: \"Should get 404 error\")\n        var error: NSError?\n        let firstMockUrl = \"https://demo-res.cloudinary.com/image/upload/c_fill,dpr_3.0,f_heic,g_auto,h_100,q_auto,w_100/v1/some_invalid_url\"\n        let secondMockUrl = \"https://httpbin.org/status/404\"\n\n        cloudinarySecured.createDownloader().fetchImage(firstMockUrl).responseImage({ (_, errorRes) in\n            error = errorRes\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n        verify404ErrorCode(in: error)\n\n        expectation = self.expectation(description: \"Should get 404 error\")\n        cloudinarySecured.createDownloader().fetchImage(secondMockUrl).responseImage({ (_, errorRes) in\n            error = errorRes\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n        verify404ErrorCode(in: error)\n    }\n\n    private func verify404ErrorCode(in error: Error?) {\n        XCTAssertNotNil(error, \"should get an error\")\n        XCTAssertNotNil((error! as NSError).userInfo[\"statusCode\"], \"should get a statusCode in user info\")\n\n        let statusCode = (error! as NSError).userInfo[\"statusCode\"] as! Int\n        XCTAssertTrue(statusCode == 404, \"Mock error should be 404 in this test\")\n        let httpStatusCode = HTTPStatusCode(rawValue: statusCode)\n        XCTAssertNotNil(httpStatusCode, \"should get a case\")\n        XCTAssertTrue(httpStatusCode?.rawValue == 404)\n    }\n\n    func test_downloadImage_shouldDownloadImage() {\n        XCTAssertNotNil(cloudinarySecured.config.apiSecret, \"Must set api secret for this test\")\n\n        var expectation = self.expectation(description: \"Upload should succeed\")\n\n        var publicId: String?\n        uploadFile().response({ (result, error) in\n            XCTAssertNil(error)\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n\n        expectation = self.expectation(description: \"test_downloadImage_shouldDownloadImage Download should succeed\")\n\n        var response: UIImage?\n        var error: NSError?\n\n        let url = cloudinarySecured!.createUrl().generate(pubId)\n        cloudinarySecured.createDownloader().fetchImage(url!).responseImage({ (responseImage, errorRes) in\n            response = responseImage\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(response, \"response should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n    func test_downloadImageWithCache_shouldCacheAndRemoveImage() {\n        cloudinarySecured.enableUrlCache = true\n        downloadImageWithCache_shouldCacheImage(cloudinaryObject: cloudinarySecured)\n    }\n    func test_downloadImageWithoutCache_shouldCacheImage() {\n        downloadImageWithoutCache_shouldNotCacheImage(cloudinaryObject: cloudinarySecured)\n    }\n\n    func test_downloadImageWithCache_emptyInit_shouldCacheImage() {\n\n        // Given\n        let config: CLDConfiguration\n        if let url  = Bundle(for: type(of: self)).infoDictionary?[\"cldCloudinaryUrl\"] as? String, url.count > 0 {\n            config  = CLDConfiguration(cloudinaryUrl: url)!\n        } else {\n            config  = CLDConfiguration.initWithEnvParams() ?? CLDConfiguration(cloudinaryUrl: \"cloudinary://a:b@test123\")!\n        }\n\n        // When\n        let tempSut = CLDCloudinary(configuration: config, networkAdapter: nil, downloadAdapter: nil, sessionConfiguration: nil, downloadSessionConfiguration: nil)\n        tempSut.enableUrlCache = true\n\n        downloadImageWithCache_shouldCacheImage(cloudinaryObject: tempSut)\n    }\n    func test_downloadImageWithoutCache_emptyInit_shouldCacheImage() {\n\n        // Given\n        let config: CLDConfiguration\n        if let url  = Bundle(for: type(of: self)).infoDictionary?[\"cldCloudinaryUrl\"] as? String, url.count > 0 {\n            config  = CLDConfiguration(cloudinaryUrl: url)!\n        } else {\n            config  = CLDConfiguration.initWithEnvParams() ?? CLDConfiguration(cloudinaryUrl: \"cloudinary://a:b@test123\")!\n        }\n\n        // When\n        let tempSut = CLDCloudinary(configuration: config, networkAdapter: nil, downloadAdapter: nil, sessionConfiguration: nil, downloadSessionConfiguration: nil)\n\n        downloadImageWithoutCache_shouldNotCacheImage(cloudinaryObject: tempSut)\n    }\n}\n\nextension DownloaderTests {\n\n    // MARK: - cache by cloudinary\n    func downloadImageWithCache_shouldCacheImage(cloudinaryObject: CLDCloudinary) {\n\n        XCTAssertNotNil(cloudinaryObject.config.apiSecret, \"Must set api secret for this test\")\n\n        // When\n        var expectation = self.expectation(description: \"Upload should succeed\")\n\n        /// upload file to get publicId\n        var publicId: String?\n        uploadFile().response({ (result, error) in\n            XCTAssertNil(error)\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n\n        expectation = self.expectation(description: \"Download 1 should succeed\")\n\n        var response: UIImage?\n        /// download image by publicId - first time, no cache yet\n        let url = cloudinaryObject.createUrl().generate(pubId)\n        cloudinaryObject.createDownloader().fetchImage(url!).responseImage({ (responseImage, errorRes) in\n            response = responseImage\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        expectation = self.expectation(description: \"Download 2 should succeed\")\n\n        var responseCached: UIImage?\n        /// download image by publicId - should get from cache so responses should be equal\n        cloudinaryObject.createDownloader().fetchImage(url!).responseImage({ (responseImage, errorRes) in\n            responseCached = responseImage\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertEqual(response?.pngData()?.count, responseCached?.pngData()?.count, \"Images should be equal because it is the image we cached\")\n\n        expectation = self.expectation(description: \"Download 3 should succeed\")\n\n        /// remove from cache and re-download - image should be different\n//        cloudinaryObject.removeFromCache(key: url!)\n        cloudinaryObject.createDownloader().fetchImage(url!).responseImage({ (responseImage, errorRes) in\n            responseCached = responseImage\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotEqual(response, responseCached, \"Images should be differet because image was removed from cache\")\n    }\n    func downloadImageWithoutCache_shouldNotCacheImage(cloudinaryObject: CLDCloudinary) {\n\n        XCTAssertNotNil(cloudinaryObject.config.apiSecret, \"Must set api secret for this test\")\n\n        // Given\n        var publicId: String?\n        var response: UIImage?\n        var error: NSError?\n        var responseCached: UIImage?\n\n        cloudinaryObject.cacheMaxMemoryTotalCost = 20\n        cloudinaryObject.cacheMaxDiskCapacity    = 20\n\n        // When\n        var expectation = self.expectation(description: \"Upload should succeed\")\n\n        /// upload file to get publicId\n        uploadFile().response({ (result, error) in\n            XCTAssertNil(error)\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n\n        expectation = self.expectation(description: \"downloadImageWithoutCache_shouldNotCacheImage Download 1 should succeed\")\n\n        let url = cloudinaryObject.createUrl().generate(pubId)\n\n        /// download image that will not get cached due to low capacity\n        cloudinaryObject.createDownloader().fetchImage(url!).responseImage({ (responseImage, errorRes) in\n            response = responseImage\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        expectation = self.expectation(description: \"downloadImageWithoutCache_shouldNotCacheImage Download 2 should succeed\")\n\n        /// download again (should not get the image from cache due to low capacity)\n        cloudinaryObject.createDownloader().fetchImage(url!).responseImage({ (responseImage, errorRes) in\n            responseCached = responseImage\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotEqual(response, responseCached, \"Images should be not same because the size of the cache is too small\")\n        XCTAssertNotNil(response, \"response should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/ManagementApiTests.swift",
    "content": "//\n//  ManagementApiTests.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\n\nclass ManagementApiTests: NetworkBaseTest {\n    \n    // MARK: - rename\n    func testRename() {\n        \n        let expectation = self.expectation(description: \"Rename should succeed\")\n        \n        var result: CLDRenameResult?\n        var error: Error?\n        \n        uploadFile().response({ (uploadResult, uploadError) in\n            if let publicId = uploadResult?.publicId {\n                let toRename = publicId + \"__APPENDED STRING\"\n                self.cloudinary!.createManagementApi().rename(publicId, to: toRename).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"response should not be nil\")\n    }\n\n    func testRenameWithParams() {\n\n           let expectation = self.expectation(description: \"Rename should succeed\")\n\n           var result: CLDRenameResult?\n           var error: Error?\n\n           uploadFile().response({ (uploadResult, uploadError) in\n               if let publicId = uploadResult?.publicId {\n                   let toRename = publicId + \"__APPENDED STRING\"\n                   self.cloudinary!.createManagementApi().rename(publicId, to: toRename, overwrite: true, invalidate: true).response({ (resultRes, errorRes) in\n                       result = resultRes\n                       error = errorRes\n\n                       expectation.fulfill()\n                   })\n               }\n               else {\n                   error = uploadError\n                   expectation.fulfill()\n               }\n           })\n\n           waitForExpectations(timeout: timeout, handler: nil)\n\n           XCTAssertNil(error, \"error should be nil\")\n           XCTAssertNotNil(result, \"response should not be nil\")\n       }\n\n    func testRenameWithRenameParams() throws {\n        try XCTSkipUnless(NetworkTestUtils.skipFolderDecouplingTest(), \"prevents redundant call to Cloudinary PAID Folder Decoupling service. to allow Folder Decoupling service testing - set to true\")\n        let expectation = self.expectation(description: \"Rename should succeed\")\n        \n        var result: CLDRenameResult?\n        var error: Error?\n        \n        uploadFile().response({ (uploadResult, uploadError) in\n            if let publicId = uploadResult?.publicId {\n                let toRename = publicId + \"__APPENDED STRING\"\n                let params = CLDRenameRequestParams(fromPublicId: publicId, toPublicId: toRename, notificationUrl: \"http://www.test.com\", context: true, metadata: true)\n                self.cloudinary!.createManagementApi().rename(publicId, to: toRename, overwrite: true, invalidate: true, params: params).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"response should not be nil\")\n        XCTAssertNotNil(result?.metadataObject, \"metadata should not be nil\")\n    }\n    \n    // MARK: - explicit\n    func testExplicit() {\n        \n        let expectation = self.expectation(description: \"Explicit should succeed\")\n        \n        var result: CLDExplicitResult?\n        var error: Error?\n        \n        var publicId: String = \"\"\n        var version: String = \"\"\n        var eager: [CLDEagerResult] = []\n        let trans = CLDTransformation().setCrop(.scale).setWidth(2.0)\n        let resource = TestResourceType.borderCollie\n        uploadFile(resource).response({ (uploadResult, uploadError) in\n            if let pubId = uploadResult?.publicId {\n                publicId = pubId\n                let params = CLDExplicitRequestParams()\n                params.setEager([trans])\n                self.cloudinary!.createManagementApi().explicit(publicId, type: .upload, params: params, completionHandler: { (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    version = result?.version ?? \"\"\n                    eager = result?.eager ?? []\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"response should not be nil\")\n        let derivedUrl = eager.first?.secureUrl ?? \"\"\n        cloudinary?.config.analytics = false\n        if let url = cloudinary!.createUrl().setFormat(resource.resourceExtension).setVersion(version).setTransformation(trans).generate(publicId){\n            XCTAssertEqual(url, derivedUrl)\n        } else{\n            XCTFail(\"url should not be nil\")\n        }\n    }\n    func testExplicitAsync(){\n        let expectation = self.expectation(description: \"Explicit should succeed\")\n        \n        var result: CLDExplicitResult?\n        var error: Error?\n\n        let trans = CLDTransformation().setCrop(.scale).setWidth(2.0)\n        let resource = TestResourceType.borderCollie\n        uploadFile(resource).response({ (uploadResult, uploadError) in\n            if let pubId = uploadResult?.publicId {\n                let params = CLDExplicitRequestParams()\n                    .setEager([trans])\n                    .setAsync(true)\n                \n                self.cloudinary!.createManagementApi().explicit(pubId, type: .upload, params: params, completionHandler: { (resultRes, errorRes) in\n                    result = resultRes\n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"response should not be nil\")\n        XCTAssertEqual(result?.resultJson[\"status\"] as? String, \"pending\")\n    }\n    \n    // MARK: - tags\n    func testTags() {\n        \n        var expectation = self.expectation(description: \"Adding a tag should succeed\")\n        \n        var result: CLDTagResult?\n        var error: Error?\n        \n        var uploadedPublicId: String = \"\"\n        // first upload\n        uploadFile().response({ (uploadResult, uploadError) in\n            if let pubId = uploadResult?.publicId {\n                uploadedPublicId = pubId\n                \n                // test adding a tag\n                self.cloudinary!.createManagementApi().addTag(\"tag1\", publicIds: [uploadedPublicId]).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.publicIds?.first ?? \"\", uploadedPublicId)\n        \n        \n        // Reaplace tag\n        result = nil\n        error = nil\n        expectation = self.expectation(description: \"Replacing a tag should succeed\")\n        let replacedTag = \"replaced_tag\"\n        cloudinary!.createManagementApi().replaceTag(replacedTag, publicIds: [uploadedPublicId]) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.publicIds?.first ?? \"\", uploadedPublicId)\n        \n        // Remove tag\n        result = nil\n        error = nil\n        expectation = self.expectation(description: \"Removing a tag should succeed\")\n        cloudinary!.createManagementApi().removeTag(replacedTag, publicIds: [uploadedPublicId]) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.publicIds?.first ?? \"\", uploadedPublicId)\n    }\n    \n    func testTagsAsArray() {\n        let tagsArray = [\"tag1\",\"tag2\",\"tag3\"]\n        \n        var expectation = self.expectation(description: \"Adding tags as an array should succeed\")\n        \n        var result: CLDTagResult?\n        var error: Error?\n        \n        var uploadedPublicId: String = \"\"\n        // first upload\n        uploadFile().response({ (uploadResult, uploadError) in\n            if let pubId = uploadResult?.publicId {\n                uploadedPublicId = pubId\n                \n                // test adding a tags\n                self.cloudinary!.createManagementApi().addTag(tagsArray, publicIds: [uploadedPublicId]).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.publicIds?.first ?? \"\", uploadedPublicId)\n        \n        // Reaplace tag\n        result = nil\n        error = nil\n        expectation = self.expectation(description: \"Replacing tags as an array should succeed\")\n        let replacedTag = [\"replaced_tag\", \"replaced_tag2\"]\n        cloudinary!.createManagementApi().replaceTag(replacedTag, publicIds: [uploadedPublicId]) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.publicIds?.first ?? \"\", uploadedPublicId)\n        \n        // Remove tags\n        result = nil\n        error = nil\n        expectation = self.expectation(description: \"Removing tags as an array should succeed\")\n        cloudinary!.createManagementApi().removeTag(tagsArray, publicIds: [uploadedPublicId]) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.publicIds?.first ?? \"\", uploadedPublicId)\n    }\n    \n    \n    \n    \n    // MARK: - text\n    func testGenerateText() {\n        \n        let expectation = self.expectation(description: \"Generate text should succeed\")\n        \n        var result: CLDTextResult?\n        var error: Error?\n        let params = CLDTextRequestParams().setFontStyle(.italic).setFontColor(\"blue\").setTextDecoration(.underline)\n        cloudinary!.createManagementApi().text(\"Hello World\", params: params) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n    }\n    \n    // MARK: - sprite\n    func testGenerateSprite() {\n        \n        let uploadParams = CLDUploadRequestParams()\n        let tag = \"sprite_test_tag\"\n        uploadParams.setTags([tag])\n        let expectation1 = self.expectation(description: \"Upload first image\")\n        let expectation2 = self.expectation(description: \"Upload second image\")\n        uploadFile(params: uploadParams).response({ (r, e) in\n            expectation1.fulfill()\n            }\n        )\n        uploadFile(params: uploadParams).response({ (r, e) in\n            expectation2.fulfill()\n            }\n        )\n        waitForExpectations(timeout: longTimeout)\n\n        let expectation = self.expectation(description: \"Generating sprite should succeed\")\n        var result: CLDSpriteResult?\n        var error: Error?\n        let width = 120, height = 25\n        let params = CLDSpriteRequestParams().setTransformation(CLDTransformation().setWidth(width).setHeight(height))\n        cloudinary!.createManagementApi().generateSprite(tag, params: params) { (resultRes, errorRes) in\n                result = resultRes\n                error = errorRes\n                expectation.fulfill()\n        }\n        \n        \n        waitForExpectations(timeout: longTimeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertGreaterThan(result?.imageInfos?.count ?? 0, 1)\n        \n        guard let imageInfo = result?.imageInfos?.first?.1 else {\n            XCTFail(\"should have at least one image info.\")\n            return\n        }\n        \n        XCTAssertEqual(imageInfo.height, height)\n        XCTAssertEqual(imageInfo.width, width)\n    }\n    \n    // MARK: - multi\n    func testMulti() {\n        \n        let uploadParams = CLDUploadRequestParams()\n        let tag = \"multi_test_tag\"\n        uploadParams.setTags([tag])\n        let expectation1 = self.expectation(description: \"Upload first image\")\n        let expectation2 = self.expectation(description: \"Upload second image\")\n\n        uploadFile(params: uploadParams).response({ (r, e) in\n            expectation1.fulfill()\n            }\n        )\n        uploadFile(params: uploadParams).response({ (r, e) in\n            expectation2.fulfill()\n            }\n        )\n        waitForExpectations(timeout: longTimeout)\n\n        let expectation = self.expectation(description: \"Generating multi should succeed\")\n        var result: CLDMultiResult?\n        var error: Error?\n        let params = CLDMultiRequestParams().setTransformation(CLDTransformation().setWidth(120).setHeight(25))\n        cloudinary!.createManagementApi().multi(tag, params: params) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: longTimeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        let multiUrl = result?.url\n        XCTAssertNotNil(multiUrl)\n        if let multiUrl = multiUrl {\n            let gifRange = multiUrl.range(of: \".gif\")\n            XCTAssertNotNil(gifRange)\n            XCTAssertEqual(multiUrl.distance(from: multiUrl.startIndex, to: gifRange!.lowerBound), multiUrl.count - 4)\n        }\n    }\n    \n    // MARK: - delete by token\n    func testDeleteByToken() {\n        \n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var deleteToken: String?\n        let uploadParams = CLDUploadRequestParams()\n        uploadParams.setReturnDeleteToken(true)\n        uploadFile(params: uploadParams).response({ (result, error) in\n            deleteToken = result?.deleteToken\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let token = deleteToken else {\n            XCTFail(\"Delete token should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"Delete by token should succeed\")\n        var result: CLDDeleteResult?\n        var error: Error?\n        \n        // test the params\n        let params = CLDDeleteByTokenRequestParams(params: [\"token\" : token])\n        \n        cloudinary!.createManagementApi().deleteByToken(token, params: params) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.result ?? \"\", \"ok\")\n    }\n\n    // MARK: - destroy\n    func testDestroy() {\n        \n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var publicId: String?\n        uploadFile().response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"Destroy should succeed\")\n        var result: CLDDeleteResult?\n        var error: Error?\n        let params = CLDDestroyRequestParams().setInvalidate(true)\n        cloudinary!.createManagementApi().destroy(pubId, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.result ?? \"\", \"ok\")\n    }\n    func testDestroyWithSignature() {\n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var publicId: String?\n        uploadFile().response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"Destroy should succeed\")\n        var result: CLDDeleteResult?\n        var error: Error?\n        let params = CLDDestroyRequestParams()\n        \n        let timestamp = Int(Date().timeIntervalSince1970)\n        var paramsToSign: [String : Any] = [:]\n        paramsToSign[\"public_id\"] = pubId\n        paramsToSign[\"timestamp\"] = String(describing: timestamp)\n        let signatureStr = cloudinarySignParamsUsingSecret(paramsToSign, cloudinaryApiSecret: (cloudinary?.config.apiSecret!)!, signatureVersion: cloudinary?.config.signatureVesion)\n        let signature = CLDSignature(signature: signatureStr, timestamp: NSNumber(integerLiteral: timestamp))\n        params.setSignature (signature)\n\n        cloudinaryNoSecret!.createManagementApi().destroy(pubId, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n        \n        XCTAssertEqual(result?.result ?? \"\", \"ok\")\n    }\n    \n    // MARK: - explode\n    func testExplode() {\n        \n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var publicId: String?\n        uploadFile(.pdf).response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"Explode should succeed\")\n        var result: CLDExplodeResult?\n        var error: Error?\n        let params = CLDExplodeRequestParams().setType(.upload)\n        cloudinary!.createManagementApi().explode(pubId, transformation: CLDTransformation().setWidth(306).setHeight(396).setPage(\"all\"), params: params) { (resultRes: CLDExplodeResult?, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.status ?? \"\", \"processing\")\n    }\n    \n    // MARK: - insufficient timeout\n    func test_renameWithTimeout_insufficientTimeOut_requestShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDRenameResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"rename should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if let publicId = uploadResult?.publicId {\n                let toRename = publicId + \"__APPENDED STRING\"\n                self.cloudinaryInsufficientTimeout!.createManagementApi().rename(publicId, to: toRename).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    func test_explicitWithTimeout_insufficientTimeOut_callShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDExplicitResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"explicit should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if let publicId = uploadResult?.publicId {\n                self.cloudinaryInsufficientTimeout!.createManagementApi().explicit(publicId, type: .facebook).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    func test_destroyWithTimeout_insufficientTimeOut_callShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDDeleteResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"destroy should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if let publicId = uploadResult?.publicId {\n                self.cloudinaryInsufficientTimeout!.createManagementApi().destroy(publicId).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    func test_addTagWithTimeout_insufficientTimeOut_callShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDTagResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"addTag should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if let publicId = uploadResult?.publicId {\n                self.cloudinaryInsufficientTimeout!.createManagementApi().addTag(\"tag1\", publicIds: [publicId]).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    func test_replaceTagWithTimeout_insufficientTimeOut_callShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDTagResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"replaceTag should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if let publicId = uploadResult?.publicId {\n                self.cloudinaryInsufficientTimeout!.createManagementApi().replaceTag(\"tag1\", publicIds: [publicId]).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    func test_removeTagWithTimeout_insufficientTimeOut_callShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDTagResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"removeTag should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if let publicId = uploadResult?.publicId {\n                self.cloudinaryInsufficientTimeout!.createManagementApi().removeTag(\"tag1\", publicIds: [publicId]).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    func test_textWithTimeout_insufficientTimeOut_callShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDTextResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"text should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if (uploadResult?.publicId) != nil {\n                self.cloudinaryInsufficientTimeout!.createManagementApi().text(\"tag1\").response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    func test_spriteWithTimeout_insufficientTimeOut_callShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDSpriteResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"sprite should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if (uploadResult?.publicId) != nil {\n                self.cloudinaryInsufficientTimeout!.createManagementApi().generateSprite(\"tag1\").response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    func test_multiWithTimeout_insufficientTimeOut_callShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDMultiResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"multi should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if (uploadResult?.publicId) != nil {\n                self.cloudinaryInsufficientTimeout!.createManagementApi().multi(\"tag1\").response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    func test_deleteByTokenWithTimeout_insufficientTimeOut_callShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDDeleteResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"delete by token should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if (uploadResult?.publicId) != nil {\n                self.cloudinaryInsufficientTimeout!.createManagementApi().deleteByToken(\"tag1\").response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    func test_explodeWithTimeout_insufficientTimeOut_callShouldRespectTimeout() {\n        \n        // Given\n        var result: CLDExplodeResult?\n        var error: Error?\n        \n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"explode should fail\")\n        \n        // When\n        uploadFile().response({ (uploadResult, uploadError) in\n            if let publicId = uploadResult?.publicId {\n                self.cloudinaryInsufficientTimeout!.createManagementApi().explode(publicId, transformation: CLDTransformation.init()).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        var actualResult = String()\n            \n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n        \n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    \n    // MARK: - sufficient timeout\n    func test_renameWithTimeout_sufficientTimeOut_callShouldRespectTimeout() {\n        \n        let expectation = self.expectation(description: \"Rename should succeed\")\n        \n        var result: CLDRenameResult?\n        var error: Error?\n        \n        uploadFile().response({ (uploadResult, uploadError) in\n            if let publicId = uploadResult?.publicId {\n                let toRename = publicId + \"__APPENDED STRING\"\n                self.cloudinarySufficientTimeout!.createManagementApi().rename(publicId, to: toRename).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"response should not be nil\")\n    }\n    func test_explicitWithTimeout_sufficientTimeOut_callShouldRespectTimeout() {\n        \n        let expectation = self.expectation(description: \"Explicit should succeed\")\n        \n        var result: CLDExplicitResult?\n        var error: Error?\n        \n        var publicId: String = \"\"\n        var version: String = \"\"\n        var eager: [CLDEagerResult] = []\n        let trans = CLDTransformation().setCrop(.scale).setWidth(2.0)\n        let resource = TestResourceType.borderCollie\n        uploadFile(resource).response({ (uploadResult, uploadError) in\n            if let pubId = uploadResult?.publicId {\n                publicId = pubId\n                let params = CLDExplicitRequestParams()\n                params.setEager([trans])\n                self.cloudinarySufficientTimeout!.createManagementApi().explicit(publicId, type: .upload, params: params, completionHandler: { (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    \n                    version = result?.version ?? \"\"\n                    eager = result?.eager ?? []\n                    \n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"response should not be nil\")\n        let derivedUrl = eager.first?.secureUrl ?? \"\"\n        \n        if let url = cloudinarySufficientTimeout!.createUrl().setFormat(resource.resourceExtension).setVersion(version).setTransformation(trans).generate(publicId){\n            XCTAssertEqual(url, derivedUrl)\n        } else{\n            XCTFail(\"url should not be nil\")\n        }\n    }\n    func test_tagsWithTimeout_sufficientTimeOut_callShouldRespectTimeout() {\n        \n        var expectation = self.expectation(description: \"Adding a tag should succeed\")\n        \n        var result: CLDTagResult?\n        var error: Error?\n        \n        var uploadedPublicId: String = \"\"\n        // first upload\n        uploadFile().response({ (uploadResult, uploadError) in\n            if let pubId = uploadResult?.publicId {\n                uploadedPublicId = pubId\n                \n                // test adding a tag\n                self.cloudinarySufficientTimeout!.createManagementApi().addTag(\"tag1\", publicIds: [uploadedPublicId]).response({ (resultRes, errorRes) in\n                    result = resultRes\n                    error = errorRes\n                    expectation.fulfill()\n                })\n            }\n            else {\n                error = uploadError\n                expectation.fulfill()\n            }\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.publicIds?.first ?? \"\", uploadedPublicId)\n        \n        \n        // Reaplace tag\n        result = nil\n        error = nil\n        expectation = self.expectation(description: \"Replacing a tag should succeed\")\n        let replacedTag = \"replaced_tag\"\n        cloudinarySufficientTimeout!.createManagementApi().replaceTag(replacedTag, publicIds: [uploadedPublicId]) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.publicIds?.first ?? \"\", uploadedPublicId)\n        \n        // Remove tag\n        result = nil\n        error = nil\n        expectation = self.expectation(description: \"Removing a tag should succeed\")\n        cloudinarySufficientTimeout!.createManagementApi().removeTag(replacedTag, publicIds: [uploadedPublicId]) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.publicIds?.first ?? \"\", uploadedPublicId)\n    }\n    func test_generateTextWithTimeout_sufficientTimeOut_callShouldRespectTimeout() {\n        \n        let expectation = self.expectation(description: \"Generate text should succeed\")\n        \n        var result: CLDTextResult?\n        var error: Error?\n        let params = CLDTextRequestParams().setFontStyle(.italic).setFontColor(\"blue\").setTextDecoration(.underline)\n        cloudinarySufficientTimeout!.createManagementApi().text(\"Hello World\", params: params) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n    }\n    func test_generateSpriteWithTimeout_sufficientTimeOut_callShouldRespectTimeout() {\n        \n        let uploadParams = CLDUploadRequestParams()\n        let tag = \"sprite_test_tag\"\n        uploadParams.setTags([tag])\n        let expectation1 = self.expectation(description: \"Upload first image\")\n        let expectation2 = self.expectation(description: \"Upload second image\")\n        uploadFile(params: uploadParams).response({ (r, e) in\n            expectation1.fulfill()\n            }\n        )\n        uploadFile(params: uploadParams).response({ (r, e) in\n            expectation2.fulfill()\n            }\n        )\n        waitForExpectations(timeout: longTimeout)\n\n        let expectation = self.expectation(description: \"Generating sprite should succeed\")\n        var result: CLDSpriteResult?\n        var error: Error?\n        let width = 120, height = 25\n        let params = CLDSpriteRequestParams().setTransformation(CLDTransformation().setWidth(width).setHeight(height))\n        cloudinarySufficientTimeout!.createManagementApi().generateSprite(tag, params: params) { (resultRes, errorRes) in\n                result = resultRes\n                error = errorRes\n                expectation.fulfill()\n        }\n        \n        \n        waitForExpectations(timeout: longTimeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertGreaterThan(result?.imageInfos?.count ?? 0, 1)\n        \n        guard let imageInfo = result?.imageInfos?.first?.1 else {\n            XCTFail(\"should have at least one image info.\")\n            return\n        }\n        \n        XCTAssertEqual(imageInfo.height, height)\n        XCTAssertEqual(imageInfo.width, width)\n    }\n    func test_multiWithTimeout_sufficientTimeOut_callShouldRespectTimeout() {\n        \n        let uploadParams = CLDUploadRequestParams()\n        let tag = \"multi_test_tag\"\n        uploadParams.setTags([tag])\n        let expectation1 = self.expectation(description: \"Upload first image\")\n        let expectation2 = self.expectation(description: \"Upload second image\")\n\n        uploadFile(params: uploadParams).response({ (r, e) in\n            expectation1.fulfill()\n            }\n        )\n        uploadFile(params: uploadParams).response({ (r, e) in\n            expectation2.fulfill()\n            }\n        )\n        waitForExpectations(timeout: longTimeout)\n\n        let expectation = self.expectation(description: \"Generating multi should succeed\")\n        var result: CLDMultiResult?\n        var error: Error?\n        let params = CLDMultiRequestParams().setTransformation(CLDTransformation().setWidth(120).setHeight(25))\n        cloudinarySufficientTimeout!.createManagementApi().multi(tag, params: params) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: longTimeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        let multiUrl = result?.url\n        XCTAssertNotNil(multiUrl)\n        if let multiUrl = multiUrl {\n            let gifRange = multiUrl.range(of: \".gif\")\n            XCTAssertNotNil(gifRange)\n            XCTAssertEqual(multiUrl.distance(from: multiUrl.startIndex, to: gifRange!.lowerBound), multiUrl.count - 4)\n        }\n    }\n    func test_deleteByTokenWithTimeout_sufficientTimeOut_callShouldRespectTimeout() {\n        \n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var deleteToken: String?\n        let uploadParams = CLDUploadRequestParams()\n        uploadParams.setReturnDeleteToken(true)\n        uploadFile(params: uploadParams).response({ (result, error) in\n            deleteToken = result?.deleteToken\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let token = deleteToken else {\n            XCTFail(\"Delete token should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"Delete by token should succeed\")\n        var result: CLDDeleteResult?\n        var error: Error?\n        \n        // test the params\n        let params = CLDDeleteByTokenRequestParams(params: [\"token\" : token])\n        \n        cloudinarySufficientTimeout!.createManagementApi().deleteByToken(token, params: params) { (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.result ?? \"\", \"ok\")\n    }\n    func test_destroyWithTimeout_sufficientTimeOut_callShouldRespectTimeout() {\n        \n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var publicId: String?\n        uploadFile().response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"Destroy should succeed\")\n        var result: CLDDeleteResult?\n        var error: Error?\n        let params = CLDDestroyRequestParams().setInvalidate(true)\n        cloudinarySufficientTimeout!.createManagementApi().destroy(pubId, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.result ?? \"\", \"ok\")\n    }\n    func test_explodeWithTimeout_sufficientTimeOut_callShouldRespectTimeout() {\n        \n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var publicId: String?\n        uploadFile(.pdf).response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"Explode should succeed\")\n        var result: CLDExplodeResult?\n        var error: Error?\n        let params = CLDExplodeRequestParams().setType(.upload)\n        cloudinarySufficientTimeout!.createManagementApi().explode(pubId, transformation: CLDTransformation().setWidth(306).setHeight(396).setPage(\"all\"), params: params) { (resultRes: CLDExplodeResult?, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        }\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n\n        XCTAssertEqual(result?.status ?? \"\", \"processing\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/NetworkBaseTests/NetworkBaseTest.swift",
    "content": "//\n//  NetworkBaseTest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport XCTest\nimport Cloudinary\nimport AVKit\n\nclass NetworkBaseTest: BaseTestCase {\n    \n    let longTimeout: TimeInterval = 60.0\n    \n    var cloudinary: CLDCloudinary?\n    var cloudinaryInsufficientTimeout: CLDCloudinary?\n    var cloudinarySufficientTimeout: CLDCloudinary?\n    var cloudinaryNoSecret: CLDCloudinary!\n    var cloudinarySecured:CLDCloudinary!\n    \n    // MARK: - Lifcycle\n    \n    override func setUp() {\n        super.setUp()\n        let config: CLDConfiguration\n\n        if let url = Bundle(for: type(of: self)).infoDictionary?[\"cldCloudinaryUrl\"] as? String, url.count > 0 {\n            config = CLDConfiguration(cloudinaryUrl: url)!\n        } else {\n            config = CLDConfiguration.initWithEnvParams() ?? CLDConfiguration(cloudinaryUrl: \"cloudinary://a:b@test123?analytics=false\")!\n            config.analytics = false\n        }\n        \n        let configInsufficientTimeout = CLDConfiguration (cloudName: config.cloudName, apiKey: config.apiKey, apiSecret: config.apiSecret, privateCdn: config.privateCdn, secure: config.secure, cdnSubdomain: config.cdnSubdomain, secureCdnSubdomain: config.secureCdnSubdomain, secureDistribution: config.secureDistribution, cname: config.cname, uploadPrefix: config.uploadPrefix, timeout: 0.01)\n        \n        let configSufficientTimeout = CLDConfiguration (cloudName: config.cloudName, apiKey: config.apiKey, apiSecret: config.apiSecret, privateCdn: config.privateCdn, secure: config.secure, cdnSubdomain: config.cdnSubdomain, secureCdnSubdomain: config.secureCdnSubdomain, secureDistribution: config.secureDistribution, cname: config.cname, uploadPrefix: config.uploadPrefix, timeout: 30000, analytics: false)\n        \n        let configNoSecret = CLDConfiguration (cloudName: config.cloudName, apiKey: config.apiKey, apiSecret: nil, privateCdn: config.privateCdn, secure: config.secure, cdnSubdomain: config.cdnSubdomain, secureCdnSubdomain: config.secureCdnSubdomain, secureDistribution: config.secureDistribution, cname: config.cname, uploadPrefix: config.uploadPrefix)\n\n        let configSecured = CLDConfiguration (cloudName: config.cloudName, apiKey: config.apiKey, apiSecret: config.apiSecret, privateCdn: config.privateCdn, secure: true, cdnSubdomain: config.cdnSubdomain, secureCdnSubdomain: config.secureCdnSubdomain, secureDistribution: config.secureDistribution, cname: config.cname, uploadPrefix: config.uploadPrefix)\n        \n        cloudinary = CLDCloudinary(configuration: config, sessionConfiguration: .default)\n        \n        cloudinaryInsufficientTimeout = CLDCloudinary(configuration: configInsufficientTimeout, sessionConfiguration: .default)\n        cloudinarySufficientTimeout = CLDCloudinary(configuration: configSufficientTimeout, sessionConfiguration: .default)\n\n        cloudinaryNoSecret = CLDCloudinary(configuration: configNoSecret, sessionConfiguration: .default)\n        cloudinarySecured = CLDCloudinary(configuration: configSecured)\n    }\n    \n    override func tearDown() {\n        super.tearDown()\n        cloudinary = nil\n        cloudinaryInsufficientTimeout = nil\n        cloudinarySufficientTimeout = nil\n        cloudinaryNoSecret = nil\n        cloudinarySecured = nil\n    }\n    \n    // MARK: - Resources\n    \n    enum TestResourceType {\n        case logo\n        case borderCollie\n        case borderCollieCropped\n        case borderCollieRotatedPng\n        case borderCollieRotatedJpg\n        case docx\n        case dog\n        case dog2\n        case pdf\n        case textImage\n\n        var fileName: String {\n            switch self {\n        \n            case .borderCollieRotatedPng:\n                if #available(iOS 12.0, *) {\n                    return \"borderCollieRotatedPng\"\n                } else {\n                    return \"borderCollieRotatedPngUnderIOS12\"\n                }\n                \n            case .borderCollieRotatedJpg:\n                if #available(iOS 12.0, *) {\n                    return \"borderCollieRotatedJpg\"\n                } else {\n                    return \"borderCollieRotatedJpgUnderIOS12\"\n                }\n                \n            default:\n                return String(describing: self)\n            }\n        }\n        \n        var resourceExtension: String {\n            \n            switch self {\n            case .logo                       : fallthrough\n            case .borderCollieRotatedPng     :\n                return \"png\"\n                \n            case .textImage                  : fallthrough\n            case .borderCollie               : fallthrough\n            case .borderCollieCropped        : fallthrough\n            case .borderCollieRotatedJpg     :\n                return \"jpg\"\n                \n            case .docx: return \"docx\"\n                \n            case .dog : fallthrough\n            case .dog2:\n                return \"mp4\"\n            \n            case .pdf : return \"pdf\"\n            }\n        }\n        \n        var url: URL {\n            let bundle = Bundle(for: NetworkBaseTest.self)\n            return bundle.url(forResource: fileName, withExtension: resourceExtension)!\n        }\n        \n        var data: Data {\n            let data = try! Data(contentsOf: url, options: .uncached)\n            return data\n        }\n    }\n    \n    // MARK: - Helpers\n    @discardableResult\n    func uploadFile(_ resource: TestResourceType = .borderCollie, params: CLDUploadRequestParams? = nil) -> CLDUploadRequest {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        var params = params\n        params?.setContext([\"test1\": \"test2\"])\n        return cloudinary!.createUploader().signedUpload(data: resource.data, params: params)\n    }\n    \n    func getImage(_ resource: TestResourceType) -> UIImage {\n        if let image = UIImage(contentsOfFile: resource.url.path) {\n            return image\n        }\n        else {\n            return UIImage()\n        }\n    }\n    \n    func getVideo(_ resource: TestResourceType) -> AVPlayerItem {\n        return AVPlayerItem(url: resource.url)\n    }\n    \n    // MARK: - skip addons\n    /**\n     Override this variable to skip addons tests in order to prevent account related failures and to save addons quota.\n     If set     - all tests in this class will be skipped, unless an environment variable \"CLD_TEST_ADDONS\" is set to the addon type OR set to \"all\". You can set multiple addons separated by comma.\n     If unset - skips nothing.\n     nil by default.\n     */\n    var testingAddonType: AddonType? { nil }\n    \n    let environmentAddonsKey = \"CLD_TEST_ADDONS\"\n    \n    override func shouldSkipTest() -> Bool {\n        \n        // only skip if testingAddonType is set\n        if let testingAddonType  = testingAddonType {\n            \n            if let testableAddonsList = ProcessInfo.processInfo.environment[environmentAddonsKey] {\n                \n                let addonContainedInEnvironmentList = testableAddonsList.lowercased().contains(testingAddonType.rawValue)\n                let environmentAddonListSetToAll    = testableAddonsList.lowercased() == AddonType.all.rawValue\n                \n                return !addonContainedInEnvironmentList && !environmentAddonListSetToAll\n            }\n            \n            // environmentAddonsKey is not set but testingAddonType is set - we should skip this tests.\n            return true\n        }\n        \n        return false\n    }\n    \n    enum AddonType: String {\n        \n        case all                       = \"all\"                       // test all addons\n        case lightroom                 = \"lightroom\"                 // adobe photoshop lightroom (BETA)\n        case facialAttributesDetection = \"facialattributesdetection\" // advanced facial attributes detection\n        case rekognition               = \"rekognition\"               // amazon rekognition AI moderation, amazon rekognition auto tagging, amazon rekognition celebrity detection\n        case aspose                    = \"aspose\"                    // aspose document conversion\n        case bgRemoval                 = \"bgremoval\"                 // cloudinary AI background removal cloudinary AI background removal\n        case objectAwareCropping       = \"objectawarecropping\"       // cloudinary object-aware cropping\"\n        case google                    = \"google\"                    // google AI video moderation, google AI video transcription, google auto tagging, google automatic video tagging, google translation\n        case imagga                    = \"imagga\"                    // imagga auto tagging, imagga crop and scale\n        case jpegmini                  = \"jpegmini\"                  // JPEGmini image optimization\n        case metaDefender              = \"metadefender\"              // metaDefender anti-malware protection\n        case azure                     = \"azure\"                     // microsoft azure video indexer\n        case neuralArtwork             = \"neuralartwork\"             // neural artwork style transfer\n        case ocr                       = \"ocr\"                       // OCR text detection and extraction\n        case pixelz                    = \"pixelz\"                    // remove the background\n        case url2png                   = \"url2png\"                   // website screenshots\n        case viesus                    = \"viesus\"                    // automatic image enhancement\n        case webpurify                 = \"webpurify\"                 // webPurify image moderation\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/NetworkBaseTests/NetworkBaseTestObjc.h",
    "content": "//\n//  NetworkBaseTestObjc.h\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"ObjcBaseTestCase.h\"\n#import \"Cloudinary_Tests-Swift.h\"\n#import <AVKit/AVKit.h>\n\ntypedef enum TestResourceType: NSUInteger {\n    logo,\n    borderCollie,\n    docx,\n    dog,\n    pdf,\n    textImage\n} TestResourceType;\n\n@interface NetworkBaseTestObjc: ObjcBaseTestCase\n\n@property (nonatomic, strong, nullable) CLDCloudinary* cloudinary;\n\n- (NSString* _Nonnull)     getResourceNameBy:(TestResourceType)testResourceType;\n- (NSURL* _Nonnull)        getUrlBy         :(TestResourceType)testResourceType;\n- (NSData* _Nonnull)       getDataBy        :(TestResourceType)testResourceType;\n- (UIImage* _Nonnull)      getImageBy       :(TestResourceType)testResourceType;\n- (AVPlayerItem* _Nonnull) getVideoBy       :(TestResourceType)testResourceType;\n\n@end\n"
  },
  {
    "path": "Example/Tests/NetworkTests/NetworkBaseTests/NetworkBaseTestObjc.m",
    "content": "//\n//  NetworkBaseTestObjc.m\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <UIKit/UIKit.h>\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"Cloudinary_Tests-Swift.h\"\n#import \"NetworkBaseTestObjc.h\"\n\n@implementation NetworkBaseTestObjc\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n    \n    self.timeout = 40.0;\n    \n    CLDConfiguration* config;\n    \n    NSString *cloudinaryUrl = [[[NSBundle bundleForClass:[self class]] infoDictionary] objectForKey:@\"cldCloudinaryUrl\"];\n    \n    if (cloudinaryUrl.length) {\n        config = [[CLDConfiguration alloc] initWithCloudinaryUrl:cloudinaryUrl];\n    }\n    else {\n        \n        config = [CLDConfiguration initWithEnvParams];\n        if (config == nil) {\n            config = [[CLDConfiguration alloc] initWithCloudinaryUrl:@\"cloudinary://a:b@test123\"];\n        }\n    }\n\n    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];\n\n    self.cloudinary = [[CLDCloudinary alloc] initWithConfiguration:config networkAdapter:nil sessionConfiguration:sessionConfig];\n}\n\n- (void)tearDown {\n    [super tearDown];\n    \n    self.cloudinary = nil;\n}\n\n// MARK: - public methods\n- (NSURL* _Nonnull)getUrlBy:(TestResourceType)testResourceType {\n    \n    NSBundle *bundle = [NSBundle bundleForClass:[self class]];\n    return [bundle URLForResource:[self getResourceNameBy:testResourceType] withExtension:[self getResourceExtensionBy:testResourceType]];\n}\n\n- (NSData* _Nonnull)getDataBy:(TestResourceType)testResourceType {\n    \n    return [NSData dataWithContentsOfURL:[self getUrlBy:testResourceType] options:NSUncachedRead error:nil];\n}\n\n- (CLDUploadRequest*)uploadFileWithResource:(TestResourceType)testResourceType params:(CLDUploadRequestParams*)params {\n    \n    XCTAssertNotNil(self.cloudinary.config.apiSecret, \"Must set api secret for this test\");\n    return [[self.cloudinary createUploader] signedUploadWithData:[self getDataBy:testResourceType] params:params progress:nil completionHandler:nil];\n}\n\n-(UIImage*)getImageBy:(TestResourceType)testResourceType {\n    \n    NSBundle* bundle = [NSBundle bundleForClass:[self class]];\n    NSURL*    url    = [bundle URLForResource:[self getResourceNameBy:testResourceType] withExtension:[self getResourceExtensionBy:testResourceType]];\n    return [UIImage imageWithContentsOfFile:url.path];\n}\n\n-(AVPlayerItem*)getVideoBy:(TestResourceType)testResourceType {\n    \n    NSBundle* bundle = [NSBundle bundleForClass:[self class]];\n    NSURL*    url    = [bundle URLForResource:[self getResourceNameBy:testResourceType] withExtension:[self getResourceExtensionBy:testResourceType]];\n    return [AVPlayerItem playerItemWithURL:url];\n}\n\n// Mark: - private methods\n- (NSString*)getResourceExtensionBy:(TestResourceType)testResourceType {\n    \n    switch (testResourceType) {\n        case logo: return @\"png\";\n        break;\n        case borderCollie:\n        case textImage: return @\"jpg\";\n        break;\n        case docx: return @\"docx\";\n        break;\n        case dog: return @\"mp4\";\n        break;\n        case pdf: return @\"pdf\";\n        break;\n    }\n}\n\n- (NSString* _Nonnull)getResourceNameBy:(TestResourceType)testResourceType {\n    \n    switch (testResourceType) {\n        case logo: return @\"logo\";\n        break;\n        case borderCollie: return @\"borderCollie\";\n        break;\n        case textImage: return @\"textImage\";\n        break;\n        case docx: return @\"docx\";\n        break;\n        case dog: return @\"dog\";\n        break;\n        case pdf: return @\"pdf\";\n        break;\n    }\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/NetworkTests/NetworkTestUtils.swift",
    "content": "//\n//  NetworkTestUtils.swift\n//  Cloudinary_Tests\n//\n//  Created by Adi Mizrahi on 29/01/2025.\n//  Copyright © 2025 CocoaPods. All rights reserved.\n//\n\nimport Foundation\nclass NetworkTestUtils {\n\n    private static let environmentFolderDecoupling = \"CLD_FOLDER_DECOUPLING\"\n\n    static func skipFolderDecouplingTest() -> Bool {\n        guard let _ = ProcessInfo.processInfo.environment[environmentFolderDecoupling] else {\n            return false\n        }\n        return true\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/MockProvider/BaseMockProvider.swift",
    "content": "//\n//  BaseMockProvider.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\n\n@objcMembers public class BaseMockProvider: NSObject {\n    \n    // MARK: - upload result\n    static public var uploadResult: CLDUploadResult? {\n        guard let resultDictionary = convertToDictionary(string: jsonString()) else { return nil }\n         \n        return CLDUploadResult(json: resultDictionary)\n    }\n    \n    // MARK: - explicit result\n    static public var explicitResult: CLDExplicitResult? {\n        guard let resultDictionary = convertToDictionary(string: jsonString()) else { return nil }\n        \n        return CLDExplicitResult(json: resultDictionary)\n    }\n    \n    fileprivate static func convertToDictionary(string: String) -> [String: AnyObject]? {\n        if let data = string.data(using: .utf8) {\n            return try? JSONSerialization.jsonObject(with: data, options: []) as? [String: AnyObject]\n        }\n        return nil\n    }\n    \n    /**\n      Override this function with mock information as json string\n     */\n    class func jsonString() -> String {\n        return \"\"\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/OcrUploaderTests/ExplicitMockOcrTests.m",
    "content": "//\n//  ObjcExplicitMockOcrTests.m\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"Cloudinary_Tests-Swift.h\"\n#import \"ObjcBaseTestCase.h\"\n\n@interface ObjcExplicitMockOcrTests : ObjcBaseTestCase\n@property (nonatomic, strong, nullable) CLDExplicitResult* sut;\n@end\n\n@implementation ObjcExplicitMockOcrTests\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n    self.sut = OcrMockProvider.explicitResult;\n}\n\n- (void)tearDown {\n    [super tearDown];\n    self.sut = nil;\n}\n\n// MARK: - explicit result\n- (void)test_explicitResult_ocrParsing_ShouldParseAsExpected {\n\n    //Given\n    NSString* expectedStatus                       = @\"complete\";\n    NSString* expectedLocale                       = @\"en\";\n    NSString* expectedTextDescription              = @\"OCR test image\\nSOME FONT\\nAnother font\\nOne more\\nlast one\\n\";\n    NSString* expectedFullTextAnnotationText       = @\"OCR test image\\nSOME FONT\\nAnother font\\nOne more\\nlast one\\n\";\n    NSString* expectedLanguageCode                 = @\"en\";\n    NSString* expectedBlockType                    = @\"TEXT\";\n    NSString* expectedSymbolText                   = @\"O\";\n    \n    // Then\n    XCTAssertNotNil(self.sut.info.ocr, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.status, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.status, expectedStatus, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0], \"mock properties should not be nil\");\n    \n    // text annotations\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].locale, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].locale, expectedLocale, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].textDescription, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].textDescription, expectedTextDescription, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].boundingBlock, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].boundingBlock.vertices, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].boundingBlock.vertices[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.text, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.text, expectedFullTextAnnotationText, \"value should be equal to expected value\");\n    \n    // pages\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property.detectedLanguages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property.detectedLanguages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property.detectedLanguages[0].languageCode, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property.detectedLanguages[0].languageCode, expectedLanguageCode, \"value should be equal to expected value\");\n  \n    // blocks\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].blockType, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].blockType, expectedBlockType, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].property.detectedLanguages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].property.detectedLanguages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].property.detectedLanguages[0].languageCode, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].property.detectedLanguages[0].languageCode, expectedLanguageCode, \"value should be equal to expected value\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].boundingBox, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].boundingBox.vertices, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].boundingBox.vertices[0], \"mock properties should not be nil\");\n  \n    // paragraph\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0], \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].property.detectedLanguages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].property.detectedLanguages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].property.detectedLanguages[0].languageCode, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].property.detectedLanguages[0].languageCode, expectedLanguageCode, \"value should be equal to expected value\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].boundingBox, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].boundingBox.vertices, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].boundingBox.vertices[0], \"mock properties should not be nil\");\n    \n    // words\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0], \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0], \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].property.detectedLanguages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].property.detectedLanguages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].property.detectedLanguages[0].languageCode, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].property.detectedLanguages[0].languageCode, expectedLanguageCode, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].boundingBox, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].boundingBox.vertices, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].boundingBox.vertices[0], \"mock properties should not be nil\");\n   \n    // symbols\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].text, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].text, expectedSymbolText , \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].property.detectedLanguages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].property.detectedLanguages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].property.detectedLanguages[0].languageCode, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].property.detectedLanguages[0].languageCode, expectedLanguageCode, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].boundingBox, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].boundingBox.vertices, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].boundingBox.vertices[0], \"mock properties should not be nil\");\n}\n\n\n@end\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/OcrUploaderTests/ExplicitMockOcrTests.swift",
    "content": "//\n//  ExplicitMockOcrTests.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\n// explicitMockOcrTests created to reduce server calls to Cloudinary PAID OCR service\nclass ExplicitMockOcrTests: NetworkBaseTest {\n\n    var sut : CLDExplicitResult!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = OcrMockProvider.explicitResult\n    }\n    override func tearDown() {\n        super.tearDown()\n        sut = nil\n    }\n    \n    // MARK: - explicit result\n    func test_explicitResult_ocrParsing_ShouldParseAsExpected() {\n\n        //Given\n        let expectedStatus                       = \"complete\"\n        let expectedLocale                       = \"en\"\n        let expectedTextDescription              = \"OCR test image\\nSOME FONT\\nAnother font\\nOne more\\nlast one\\n\"\n        let expectedVerticeX                     = CGFloat(89)\n        let expectedVerticeY                     = CGFloat(87)\n        let expectedFullTextAnnotationText       = \"OCR test image\\nSOME FONT\\nAnother font\\nOne more\\nlast one\\n\"\n        let expectedPagesWidth                   = 1144\n        let expectedPagesHeight                  = 1048\n        let expectedLanguageCode                 = \"en\"\n        let expectedConfidence                   = 1\n        let expectedBlockType                    = \"TEXT\"\n        let expectedBoundingBoxVerticeX          = CGFloat(241)\n        let expectedBoundingBoxVerticeY          = CGFloat(84)\n        let expectedParagraphBoundingBoxVerticeX = CGFloat(241)\n        let expectedParagraphBoundingBoxVerticeY = CGFloat(84)\n        let expectedWordsBoundingBoxVerticeX     = CGFloat(241)\n        let expectedWordsBoundingBoxVerticeY     = CGFloat(87)\n        let expectedSymbolText                   = \"O\"\n        let expectedSymbolsBoundingBoxVerticeX   = CGFloat(241)\n        let expectedSymbolsBoundingBoxVerticeY   = CGFloat(88)\n        \n        // Then\n        XCTAssertNotNil(sut.info?.ocr, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.status, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.status, expectedStatus, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0], \"mock properties should not be nil\")\n        \n        // text annotations\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations!, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].locale, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].locale, expectedLocale, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].textDescription, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].textDescription, expectedTextDescription, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].boundingBlock, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].boundingBlock?.vertices, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].boundingBlock?.vertices![0], \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].boundingBlock?.vertices![0].x, expectedVerticeX, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].boundingBlock?.vertices![0].y, expectedVerticeY, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.text, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.text, expectedFullTextAnnotationText, \"value should be equal to expected value\")\n        \n        // pages\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].width, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].width, expectedPagesWidth, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].height, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].height, expectedPagesHeight, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages![0].languageCode, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages![0].languageCode, expectedLanguageCode, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages![0].confidence, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages![0].confidence, expectedConfidence, \"value should be equal to expected value\")\n        \n        // blocks\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].blockType, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].blockType, expectedBlockType, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages![0].languageCode, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages![0].languageCode, expectedLanguageCode, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages![0].confidence, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages![0].confidence, expectedConfidence, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].boundingBox, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].boundingBox?.vertices, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].boundingBox?.vertices![0], \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].boundingBox?.vertices![0].x, expectedBoundingBoxVerticeX, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].boundingBox?.vertices![0].y, expectedBoundingBoxVerticeY, \"value should be equal to expected value\")\n        \n        // paragraph\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0], \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages![0].languageCode, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages![0].languageCode, expectedLanguageCode, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages![0].confidence, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages![0].confidence, expectedConfidence, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].boundingBox, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].boundingBox?.vertices, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].boundingBox?.vertices![0], \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].boundingBox?.vertices![0].x, expectedParagraphBoundingBoxVerticeX, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].boundingBox?.vertices![0].y, expectedParagraphBoundingBoxVerticeY, \"value should be equal to expected value\")\n        \n        // words\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0], \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0], \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].property?.detectedLanguages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].property?.detectedLanguages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].property?.detectedLanguages![0].languageCode, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].property?.detectedLanguages![0].languageCode, expectedLanguageCode, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].boundingBox, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].boundingBox?.vertices, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].boundingBox?.vertices![0], \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].boundingBox?.vertices![0].x, expectedWordsBoundingBoxVerticeX, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].boundingBox?.vertices![0].y, expectedWordsBoundingBoxVerticeY, \"value should be equal to expected value\")\n       \n        // symbols\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].text, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].text, expectedSymbolText , \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].property?.detectedLanguages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].property?.detectedLanguages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].property?.detectedLanguages![0].languageCode, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].property?.detectedLanguages![0].languageCode, expectedLanguageCode, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].boundingBox, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].boundingBox?.vertices, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].boundingBox?.vertices![0], \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].boundingBox?.vertices![0].x, expectedSymbolsBoundingBoxVerticeX, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].boundingBox?.vertices![0].y, expectedSymbolsBoundingBoxVerticeY, \"value should be equal to expected value\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/OcrUploaderTests/OcrMockProvider.swift",
    "content": "//\n//  OcrMockProvider.swift\n//  Cloudinary_Tests\n//\n//  MockProvider.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\npublic class OcrMockProvider: BaseMockProvider {\n\n    // MARK: - json result\n    override class func jsonString() -> String {\n        \n        return \"{\\\"asset_id\\\":\\\"a63b0808cb58d34f1bb074ec7e291cf5\\\",\\\"public_id\\\":\\\"hplf6ct1tqorpelxnezi\\\",\\\"version\\\":1591790130,\\\"version_id\\\":\\\"de952b0068804f79515f2b7ef80e0046\\\",\\\"signature\\\":\\\"3c840854853511ea97b46d0bd4672713acec2e48\\\",\\\"width\\\":1144,\\\"height\\\":1048,\\\"format\\\":\\\"jpg\\\",\\\"resource_type\\\":\\\"image\\\",\\\"created_at\\\":\\\"2020-06-10T11:55:30Z\\\",\\\"tags\\\":[],\\\"bytes\\\":64893,\\\"type\\\":\\\"upload\\\",\\\"etag\\\":\\\"aa1a546faf1dad85ef49f6f6a2875602\\\",\\\"placeholder\\\":false,\\\"url\\\":\\\"http://res.cloudinary.com/ginidev/image/upload/v1591790130/hplf6ct1tqorpelxnezi.jpg\\\",\\\"secure_url\\\":\\\"https://res.cloudinary.com/ginidev/image/upload/v1591790130/hplf6ct1tqorpelxnezi.jpg\\\",\\\"access_mode\\\":\\\"public\\\",\\\"info\\\":{\\\"ocr\\\":{\\\"adv_ocr\\\":{\\\"status\\\":\\\"complete\\\",\\\"data\\\":[{\\\"textAnnotations\\\":[{\\\"locale\\\":\\\"en\\\",\\\"description\\\":\\\"OCR test image\\\\nSOME FONT\\\\nAnother font\\\\nOne more\\\\nlast one\\\\n\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":89,\\\"y\\\":87},{\\\"x\\\":1075,\\\"y\\\":87},{\\\"x\\\":1075,\\\"y\\\":492},{\\\"x\\\":89,\\\"y\\\":492}]}},{\\\"description\\\":\\\"OCR\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":241,\\\"y\\\":87},{\\\"x\\\":362,\\\"y\\\":90},{\\\"x\\\":361,\\\"y\\\":132},{\\\"x\\\":240,\\\"y\\\":129}]}},{\\\"description\\\":\\\"test\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":379,\\\"y\\\":88},{\\\"x\\\":468,\\\"y\\\":90},{\\\"x\\\":467,\\\"y\\\":132},{\\\"x\\\":378,\\\"y\\\":130}]}},{\\\"description\\\":\\\"image\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":487,\\\"y\\\":89},{\\\"x\\\":634,\\\"y\\\":92},{\\\"x\\\":633,\\\"y\\\":141},{\\\"x\\\":486,\\\"y\\\":138}]}},{\\\"description\\\":\\\"SOME\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":92,\\\"y\\\":248},{\\\"x\\\":201,\\\"y\\\":249},{\\\"x\\\":200,\\\"y\\\":312},{\\\"x\\\":91,\\\"y\\\":311}]}},{\\\"description\\\":\\\"FONT\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":224,\\\"y\\\":255},{\\\"x\\\":325,\\\"y\\\":256},{\\\"x\\\":324,\\\"y\\\":312},{\\\"x\\\":223,\\\"y\\\":311}]}},{\\\"description\\\":\\\"Another\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":508,\\\"y\\\":260},{\\\"x\\\":837,\\\"y\\\":260},{\\\"x\\\":837,\\\"y\\\":311},{\\\"x\\\":508,\\\"y\\\":311}]}},{\\\"description\\\":\\\"font\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":900,\\\"y\\\":260},{\\\"x\\\":1075,\\\"y\\\":260},{\\\"x\\\":1075,\\\"y\\\":311},{\\\"x\\\":900,\\\"y\\\":311}]}},{\\\"description\\\":\\\"One\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":90,\\\"y\\\":446},{\\\"x\\\":169,\\\"y\\\":448},{\\\"x\\\":168,\\\"y\\\":481},{\\\"x\\\":89,\\\"y\\\":479}]}},{\\\"description\\\":\\\"more\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":185,\\\"y\\\":455},{\\\"x\\\":284,\\\"y\\\":458},{\\\"x\\\":283,\\\"y\\\":484},{\\\"x\\\":184,\\\"y\\\":481}]}},{\\\"description\\\":\\\"last\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":516,\\\"y\\\":442},{\\\"x\\\":602,\\\"y\\\":441},{\\\"x\\\":602,\\\"y\\\":491},{\\\"x\\\":516,\\\"y\\\":492}]}},{\\\"description\\\":\\\"one\\\",\\\"boundingPoly\\\":{\\\"vertices\\\":[{\\\"x\\\":614,\\\"y\\\":451},{\\\"x\\\":688,\\\"y\\\":451},{\\\"x\\\":688,\\\"y\\\":479},{\\\"x\\\":614,\\\"y\\\":479}]}}],\\\"fullTextAnnotation\\\":{\\\"pages\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"width\\\":1144,\\\"height\\\":1048,\\\"blocks\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":241,\\\"y\\\":84},{\\\"x\\\":634,\\\"y\\\":92},{\\\"x\\\":633,\\\"y\\\":141},{\\\"x\\\":240,\\\"y\\\":133}]},\\\"paragraphs\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":241,\\\"y\\\":84},{\\\"x\\\":634,\\\"y\\\":92},{\\\"x\\\":633,\\\"y\\\":141},{\\\"x\\\":240,\\\"y\\\":133}]},\\\"words\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":241,\\\"y\\\":87},{\\\"x\\\":362,\\\"y\\\":90},{\\\"x\\\":361,\\\"y\\\":132},{\\\"x\\\":240,\\\"y\\\":129}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":241,\\\"y\\\":88},{\\\"x\\\":279,\\\"y\\\":89},{\\\"x\\\":278,\\\"y\\\":130},{\\\"x\\\":240,\\\"y\\\":129}]},\\\"text\\\":\\\"O\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":285,\\\"y\\\":88},{\\\"x\\\":320,\\\"y\\\":89},{\\\"x\\\":319,\\\"y\\\":130},{\\\"x\\\":284,\\\"y\\\":129}]},\\\"text\\\":\\\"C\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"SPACE\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":326,\\\"y\\\":89},{\\\"x\\\":362,\\\"y\\\":90},{\\\"x\\\":361,\\\"y\\\":130},{\\\"x\\\":325,\\\"y\\\":129}]},\\\"text\\\":\\\"R\\\"}]},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":379,\\\"y\\\":88},{\\\"x\\\":468,\\\"y\\\":90},{\\\"x\\\":467,\\\"y\\\":132},{\\\"x\\\":378,\\\"y\\\":130}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":379,\\\"y\\\":90},{\\\"x\\\":394,\\\"y\\\":90},{\\\"x\\\":393,\\\"y\\\":129},{\\\"x\\\":378,\\\"y\\\":129}]},\\\"text\\\":\\\"t\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":396,\\\"y\\\":100},{\\\"x\\\":423,\\\"y\\\":101},{\\\"x\\\":422,\\\"y\\\":131},{\\\"x\\\":395,\\\"y\\\":130}]},\\\"text\\\":\\\"e\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":427,\\\"y\\\":99},{\\\"x\\\":451,\\\"y\\\":100},{\\\"x\\\":450,\\\"y\\\":130},{\\\"x\\\":426,\\\"y\\\":129}]},\\\"text\\\":\\\"s\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"SPACE\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":454,\\\"y\\\":90},{\\\"x\\\":468,\\\"y\\\":90},{\\\"x\\\":467,\\\"y\\\":130},{\\\"x\\\":453,\\\"y\\\":130}]},\\\"text\\\":\\\"t\\\"}]},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":487,\\\"y\\\":89},{\\\"x\\\":634,\\\"y\\\":92},{\\\"x\\\":633,\\\"y\\\":141},{\\\"x\\\":486,\\\"y\\\":138}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":487,\\\"y\\\":89},{\\\"x\\\":493,\\\"y\\\":89},{\\\"x\\\":492,\\\"y\\\":128},{\\\"x\\\":486,\\\"y\\\":128}]},\\\"text\\\":\\\"i\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":500,\\\"y\\\":99},{\\\"x\\\":540,\\\"y\\\":100},{\\\"x\\\":539,\\\"y\\\":130},{\\\"x\\\":499,\\\"y\\\":129}]},\\\"text\\\":\\\"m\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":545,\\\"y\\\":100},{\\\"x\\\":572,\\\"y\\\":101},{\\\"x\\\":571,\\\"y\\\":131},{\\\"x\\\":544,\\\"y\\\":130}]},\\\"text\\\":\\\"a\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":576,\\\"y\\\":99},{\\\"x\\\":602,\\\"y\\\":100},{\\\"x\\\":601,\\\"y\\\":141},{\\\"x\\\":575,\\\"y\\\":140}]},\\\"text\\\":\\\"g\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"LINE_BREAK\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":608,\\\"y\\\":99},{\\\"x\\\":634,\\\"y\\\":100},{\\\"x\\\":633,\\\"y\\\":130},{\\\"x\\\":607,\\\"y\\\":129}]},\\\"text\\\":\\\"e\\\"}]}]}],\\\"blockType\\\":\\\"TEXT\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":92,\\\"y\\\":248},{\\\"x\\\":325,\\\"y\\\":251},{\\\"x\\\":324,\\\"y\\\":314},{\\\"x\\\":91,\\\"y\\\":311}]},\\\"paragraphs\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":92,\\\"y\\\":248},{\\\"x\\\":325,\\\"y\\\":251},{\\\"x\\\":324,\\\"y\\\":314},{\\\"x\\\":91,\\\"y\\\":311}]},\\\"words\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":92,\\\"y\\\":248},{\\\"x\\\":201,\\\"y\\\":249},{\\\"x\\\":200,\\\"y\\\":312},{\\\"x\\\":91,\\\"y\\\":311}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":92,\\\"y\\\":248},{\\\"x\\\":105,\\\"y\\\":248},{\\\"x\\\":104,\\\"y\\\":311},{\\\"x\\\":91,\\\"y\\\":311}]},\\\"text\\\":\\\"S\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":116,\\\"y\\\":256},{\\\"x\\\":135,\\\"y\\\":256},{\\\"x\\\":134,\\\"y\\\":309},{\\\"x\\\":115,\\\"y\\\":309}]},\\\"text\\\":\\\"O\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":146,\\\"y\\\":257},{\\\"x\\\":177,\\\"y\\\":257},{\\\"x\\\":176,\\\"y\\\":312},{\\\"x\\\":145,\\\"y\\\":312}]},\\\"text\\\":\\\"M\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"SPACE\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":190,\\\"y\\\":257},{\\\"x\\\":201,\\\"y\\\":257},{\\\"x\\\":200,\\\"y\\\":310},{\\\"x\\\":189,\\\"y\\\":310}]},\\\"text\\\":\\\"E\\\"}]},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":224,\\\"y\\\":255},{\\\"x\\\":325,\\\"y\\\":256},{\\\"x\\\":324,\\\"y\\\":312},{\\\"x\\\":223,\\\"y\\\":311}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":224,\\\"y\\\":256},{\\\"x\\\":237,\\\"y\\\":256},{\\\"x\\\":236,\\\"y\\\":309},{\\\"x\\\":223,\\\"y\\\":309}]},\\\"text\\\":\\\"F\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":244,\\\"y\\\":256},{\\\"x\\\":263,\\\"y\\\":256},{\\\"x\\\":262,\\\"y\\\":311},{\\\"x\\\":243,\\\"y\\\":311}]},\\\"text\\\":\\\"O\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":274,\\\"y\\\":256},{\\\"x\\\":299,\\\"y\\\":256},{\\\"x\\\":298,\\\"y\\\":309},{\\\"x\\\":273,\\\"y\\\":309}]},\\\"text\\\":\\\"N\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"LINE_BREAK\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":306,\\\"y\\\":257},{\\\"x\\\":325,\\\"y\\\":257},{\\\"x\\\":324,\\\"y\\\":308},{\\\"x\\\":305,\\\"y\\\":308}]},\\\"text\\\":\\\"T\\\"}]}]}],\\\"blockType\\\":\\\"TEXT\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":508,\\\"y\\\":260},{\\\"x\\\":1075,\\\"y\\\":260},{\\\"x\\\":1075,\\\"y\\\":311},{\\\"x\\\":508,\\\"y\\\":311}]},\\\"paragraphs\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":508,\\\"y\\\":260},{\\\"x\\\":1075,\\\"y\\\":260},{\\\"x\\\":1075,\\\"y\\\":311},{\\\"x\\\":508,\\\"y\\\":311}]},\\\"words\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":508,\\\"y\\\":260},{\\\"x\\\":837,\\\"y\\\":260},{\\\"x\\\":837,\\\"y\\\":311},{\\\"x\\\":508,\\\"y\\\":311}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":508,\\\"y\\\":264},{\\\"x\\\":553,\\\"y\\\":264},{\\\"x\\\":553,\\\"y\\\":309},{\\\"x\\\":508,\\\"y\\\":309}]},\\\"text\\\":\\\"A\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":558,\\\"y\\\":274},{\\\"x\\\":597,\\\"y\\\":274},{\\\"x\\\":597,\\\"y\\\":309},{\\\"x\\\":558,\\\"y\\\":309}]},\\\"text\\\":\\\"n\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":608,\\\"y\\\":274},{\\\"x\\\":643,\\\"y\\\":274},{\\\"x\\\":643,\\\"y\\\":311},{\\\"x\\\":608,\\\"y\\\":311}]},\\\"text\\\":\\\"o\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":656,\\\"y\\\":264},{\\\"x\\\":691,\\\"y\\\":264},{\\\"x\\\":691,\\\"y\\\":311},{\\\"x\\\":656,\\\"y\\\":311}]},\\\"text\\\":\\\"t\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":702,\\\"y\\\":260},{\\\"x\\\":741,\\\"y\\\":260},{\\\"x\\\":741,\\\"y\\\":309},{\\\"x\\\":702,\\\"y\\\":309}]},\\\"text\\\":\\\"h\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":752,\\\"y\\\":274},{\\\"x\\\":787,\\\"y\\\":274},{\\\"x\\\":787,\\\"y\\\":311},{\\\"x\\\":752,\\\"y\\\":311}]},\\\"text\\\":\\\"e\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"SPACE\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":802,\\\"y\\\":274},{\\\"x\\\":837,\\\"y\\\":274},{\\\"x\\\":837,\\\"y\\\":309},{\\\"x\\\":802,\\\"y\\\":309}]},\\\"text\\\":\\\"r\\\"}]},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":900,\\\"y\\\":260},{\\\"x\\\":1075,\\\"y\\\":260},{\\\"x\\\":1075,\\\"y\\\":311},{\\\"x\\\":900,\\\"y\\\":311}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":900,\\\"y\\\":260},{\\\"x\\\":933,\\\"y\\\":260},{\\\"x\\\":933,\\\"y\\\":309},{\\\"x\\\":900,\\\"y\\\":309}]},\\\"text\\\":\\\"f\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":944,\\\"y\\\":274},{\\\"x\\\":979,\\\"y\\\":274},{\\\"x\\\":979,\\\"y\\\":311},{\\\"x\\\":944,\\\"y\\\":311}]},\\\"text\\\":\\\"o\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":990,\\\"y\\\":274},{\\\"x\\\":1029,\\\"y\\\":274},{\\\"x\\\":1029,\\\"y\\\":309},{\\\"x\\\":990,\\\"y\\\":309}]},\\\"text\\\":\\\"n\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"LINE_BREAK\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":1040,\\\"y\\\":264},{\\\"x\\\":1075,\\\"y\\\":264},{\\\"x\\\":1075,\\\"y\\\":311},{\\\"x\\\":1040,\\\"y\\\":311}]},\\\"text\\\":\\\"t\\\"}]}]}],\\\"blockType\\\":\\\"TEXT\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":90,\\\"y\\\":446},{\\\"x\\\":284,\\\"y\\\":452},{\\\"x\\\":283,\\\"y\\\":485},{\\\"x\\\":89,\\\"y\\\":479}]},\\\"paragraphs\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":90,\\\"y\\\":446},{\\\"x\\\":284,\\\"y\\\":452},{\\\"x\\\":283,\\\"y\\\":485},{\\\"x\\\":89,\\\"y\\\":479}]},\\\"words\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":90,\\\"y\\\":446},{\\\"x\\\":169,\\\"y\\\":448},{\\\"x\\\":168,\\\"y\\\":481},{\\\"x\\\":89,\\\"y\\\":479}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":90,\\\"y\\\":446},{\\\"x\\\":120,\\\"y\\\":447},{\\\"x\\\":119,\\\"y\\\":480},{\\\"x\\\":89,\\\"y\\\":479}]},\\\"text\\\":\\\"O\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":125,\\\"y\\\":456},{\\\"x\\\":144,\\\"y\\\":457},{\\\"x\\\":143,\\\"y\\\":481},{\\\"x\\\":124,\\\"y\\\":480}]},\\\"text\\\":\\\"n\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"SPACE\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":148,\\\"y\\\":457},{\\\"x\\\":169,\\\"y\\\":458},{\\\"x\\\":168,\\\"y\\\":481},{\\\"x\\\":147,\\\"y\\\":480}]},\\\"text\\\":\\\"e\\\"}]},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":185,\\\"y\\\":455},{\\\"x\\\":284,\\\"y\\\":458},{\\\"x\\\":283,\\\"y\\\":484},{\\\"x\\\":184,\\\"y\\\":481}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":185,\\\"y\\\":456},{\\\"x\\\":215,\\\"y\\\":457},{\\\"x\\\":214,\\\"y\\\":482},{\\\"x\\\":184,\\\"y\\\":481}]},\\\"text\\\":\\\"m\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":219,\\\"y\\\":457},{\\\"x\\\":237,\\\"y\\\":458},{\\\"x\\\":236,\\\"y\\\":481},{\\\"x\\\":218,\\\"y\\\":480}]},\\\"text\\\":\\\"o\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":243,\\\"y\\\":457},{\\\"x\\\":259,\\\"y\\\":457},{\\\"x\\\":258,\\\"y\\\":480},{\\\"x\\\":242,\\\"y\\\":480}]},\\\"text\\\":\\\"r\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"LINE_BREAK\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":263,\\\"y\\\":457},{\\\"x\\\":284,\\\"y\\\":458},{\\\"x\\\":283,\\\"y\\\":481},{\\\"x\\\":262,\\\"y\\\":480}]},\\\"text\\\":\\\"e\\\"}]}]}],\\\"blockType\\\":\\\"TEXT\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":516,\\\"y\\\":442},{\\\"x\\\":688,\\\"y\\\":441},{\\\"x\\\":688,\\\"y\\\":491},{\\\"x\\\":516,\\\"y\\\":492}]},\\\"paragraphs\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\",\\\"confidence\\\":1}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":516,\\\"y\\\":442},{\\\"x\\\":688,\\\"y\\\":441},{\\\"x\\\":688,\\\"y\\\":491},{\\\"x\\\":516,\\\"y\\\":492}]},\\\"words\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":516,\\\"y\\\":442},{\\\"x\\\":602,\\\"y\\\":441},{\\\"x\\\":602,\\\"y\\\":491},{\\\"x\\\":516,\\\"y\\\":492}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":516,\\\"y\\\":443},{\\\"x\\\":563,\\\"y\\\":443},{\\\"x\\\":563,\\\"y\\\":492},{\\\"x\\\":516,\\\"y\\\":492}]},\\\"text\\\":\\\"l\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":564,\\\"y\\\":443},{\\\"x\\\":580,\\\"y\\\":443},{\\\"x\\\":580,\\\"y\\\":492},{\\\"x\\\":564,\\\"y\\\":492}]},\\\"text\\\":\\\"a\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":581,\\\"y\\\":443},{\\\"x\\\":596,\\\"y\\\":443},{\\\"x\\\":596,\\\"y\\\":492},{\\\"x\\\":581,\\\"y\\\":492}]},\\\"text\\\":\\\"s\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"SPACE\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":597,\\\"y\\\":442},{\\\"x\\\":602,\\\"y\\\":442},{\\\"x\\\":602,\\\"y\\\":491},{\\\"x\\\":597,\\\"y\\\":491}]},\\\"text\\\":\\\"t\\\"}]},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":614,\\\"y\\\":451},{\\\"x\\\":688,\\\"y\\\":451},{\\\"x\\\":688,\\\"y\\\":479},{\\\"x\\\":614,\\\"y\\\":479}]},\\\"symbols\\\":[{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":614,\\\"y\\\":451},{\\\"x\\\":663,\\\"y\\\":451},{\\\"x\\\":663,\\\"y\\\":479},{\\\"x\\\":614,\\\"y\\\":479}]},\\\"text\\\":\\\"o\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}]},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":664,\\\"y\\\":451},{\\\"x\\\":671,\\\"y\\\":451},{\\\"x\\\":671,\\\"y\\\":479},{\\\"x\\\":664,\\\"y\\\":479}]},\\\"text\\\":\\\"n\\\"},{\\\"property\\\":{\\\"detectedLanguages\\\":[{\\\"languageCode\\\":\\\"en\\\"}],\\\"detectedBreak\\\":{\\\"type\\\":\\\"LINE_BREAK\\\"}},\\\"boundingBox\\\":{\\\"vertices\\\":[{\\\"x\\\":672,\\\"y\\\":451},{\\\"x\\\":688,\\\"y\\\":451},{\\\"x\\\":688,\\\"y\\\":479},{\\\"x\\\":672,\\\"y\\\":479}]},\\\"text\\\":\\\"e\\\"}]}]}],\\\"blockType\\\":\\\"TEXT\\\"}]}],\\\"text\\\":\\\"OCR test image\\\\nSOME FONT\\\\nAnother font\\\\nOne more\\\\nlast one\\\\n\\\"}}]}}},\\\"original_filename\\\":\\\"textImage\\\"}\"\n    }\n}\n\n\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/OcrUploaderTests/UploaderMockOcrTests.m",
    "content": "//\n//  ObjcUploaderMockOcrTests.m\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"Cloudinary_Tests-Swift.h\"\n#import \"ObjcBaseTestCase.h\"\n\n@interface ObjcUploaderMockOcrTests : ObjcBaseTestCase\n@property (nonatomic, strong, nullable) CLDUploadResult* sut;\n@end\n\n@implementation ObjcUploaderMockOcrTests\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n    self.sut = OcrMockProvider.uploadResult;\n}\n\n- (void)tearDown {\n    [super tearDown];\n    self.sut = nil;\n}\n\n// MARK: - upload result\n- (void)test_uploadResult_ocrParsing_ShouldParseAsExpected {\n\n    //Given\n    NSString* expectedStatus                       = @\"complete\";\n    NSString* expectedLocale                       = @\"en\";\n    NSString* expectedTextDescription              = @\"OCR test image\\nSOME FONT\\nAnother font\\nOne more\\nlast one\\n\";\n    NSString* expectedFullTextAnnotationText       = @\"OCR test image\\nSOME FONT\\nAnother font\\nOne more\\nlast one\\n\";\n    NSString* expectedLanguageCode                 = @\"en\";\n    NSString* expectedBlockType                    = @\"TEXT\";\n    NSString* expectedSymbolText                   = @\"O\";\n    \n    // Then\n    XCTAssertNotNil(self.sut.info.ocr, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.status, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.status, expectedStatus, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0], \"mock properties should not be nil\");\n    \n    // text annotations\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].locale, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].locale, expectedLocale, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].textDescription, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].textDescription, expectedTextDescription, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].boundingBlock, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].boundingBlock.vertices, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].textAnnotations[0].boundingBlock.vertices[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.text, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.text, expectedFullTextAnnotationText, \"value should be equal to expected value\");\n    \n    // pages\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property.detectedLanguages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property.detectedLanguages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property.detectedLanguages[0].languageCode, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].property.detectedLanguages[0].languageCode, expectedLanguageCode, \"value should be equal to expected value\");\n    \n    // blocks\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].blockType, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].blockType, expectedBlockType, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].property.detectedLanguages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].property.detectedLanguages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].property.detectedLanguages[0].languageCode, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].property.detectedLanguages[0].languageCode, expectedLanguageCode, \"value should be equal to expected value\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].boundingBox, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].boundingBox.vertices, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].boundingBox.vertices[0], \"mock properties should not be nil\");\n    \n    // paragraph\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0], \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].property.detectedLanguages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].property.detectedLanguages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].property.detectedLanguages[0].languageCode, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].property.detectedLanguages[0].languageCode, expectedLanguageCode, \"value should be equal to expected value\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].boundingBox, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].boundingBox.vertices, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].boundingBox.vertices[0], \"mock properties should not be nil\");\n    \n    // words\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0], \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0], \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].property.detectedLanguages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].property.detectedLanguages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].property.detectedLanguages[0].languageCode, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].property.detectedLanguages[0].languageCode, expectedLanguageCode, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].boundingBox, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].boundingBox.vertices, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].boundingBox.vertices[0], \"mock properties should not be nil\");\n   \n    // symbols\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].text, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].text, expectedSymbolText , \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].property, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].property.detectedLanguages, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].property.detectedLanguages[0], \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].property.detectedLanguages[0].languageCode, \"mock properties should not be nil\");\n    XCTAssertEqualObjects(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].property.detectedLanguages[0].languageCode, expectedLanguageCode, \"value should be equal to expected value\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].boundingBox, \"mock properties should not be nil\");\n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].boundingBox.vertices, \"mock properties should not be nil\");\n    \n    XCTAssertNotNil(self.sut.info.ocr.advOcr.data[0].fullTextAnnotation.pages[0].blocks[0].paragraphs[0].words[0].symbols[0].boundingBox.vertices[0], \"mock properties should not be nil\");\n}\n\n\n@end\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/OcrUploaderTests/UploaderMockOcrTests.swift",
    "content": "//\n//  UploaderMockOcrTests.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\n// UploaderMockOcrTests created to reduce server calls to Cloudinary PAID OCR service\nclass UploaderMockOcrTests: NetworkBaseTest {\n\n    var sut : CLDUploadResult!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = OcrMockProvider.uploadResult\n    }\n    override func tearDown() {\n        super.tearDown()\n        sut = nil\n    }\n    \n    // MARK: - upload result\n    func test_uploadResult_ocrParsing_ShouldParseAsExpected() {\n\n        //Given\n        let expectedStatus                       = \"complete\"\n        let expectedLocale                       = \"en\"\n        let expectedTextDescription              = \"OCR test image\\nSOME FONT\\nAnother font\\nOne more\\nlast one\\n\"\n        let expectedVerticeX                     = CGFloat(89)\n        let expectedVerticeY                     = CGFloat(87)\n        let expectedFullTextAnnotationText       = \"OCR test image\\nSOME FONT\\nAnother font\\nOne more\\nlast one\\n\"\n        let expectedPagesWidth                   = 1144\n        let expectedPagesHeight                  = 1048\n        let expectedLanguageCode                 = \"en\"\n        let expectedConfidence                   = 1\n        let expectedBlockType                    = \"TEXT\"\n        let expectedBoundingBoxVerticeX          = CGFloat(241)\n        let expectedBoundingBoxVerticeY          = CGFloat(84)\n        let expectedParagraphBoundingBoxVerticeX = CGFloat(241)\n        let expectedParagraphBoundingBoxVerticeY = CGFloat(84)\n        let expectedWordsBoundingBoxVerticeX     = CGFloat(241)\n        let expectedWordsBoundingBoxVerticeY     = CGFloat(87)\n        let expectedSymbolText                   = \"O\"\n        let expectedSymbolsBoundingBoxVerticeX   = CGFloat(241)\n        let expectedSymbolsBoundingBoxVerticeY   = CGFloat(88)\n        \n        // Then\n        XCTAssertNotNil(sut.info?.ocr, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.status, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.status, expectedStatus, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0], \"mock properties should not be nil\")\n        \n        // text annotations\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations!, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].locale, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].locale, expectedLocale, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].textDescription, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].textDescription, expectedTextDescription, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].boundingBlock, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].boundingBlock?.vertices, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].boundingBlock?.vertices![0], \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].boundingBlock?.vertices![0].x, expectedVerticeX, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].textAnnotations![0].boundingBlock?.vertices![0].y, expectedVerticeY, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.text, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.text, expectedFullTextAnnotationText, \"value should be equal to expected value\")\n        \n        // pages\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].width, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].width, expectedPagesWidth, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].height, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].height, expectedPagesHeight, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages![0].languageCode, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages![0].languageCode, expectedLanguageCode, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages![0].confidence, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].property?.detectedLanguages![0].confidence, expectedConfidence, \"value should be equal to expected value\")\n        \n        // blocks\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].blockType, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].blockType, expectedBlockType, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages![0].languageCode, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages![0].languageCode, expectedLanguageCode, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages![0].confidence, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].property?.detectedLanguages![0].confidence, expectedConfidence, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].boundingBox, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].boundingBox?.vertices, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].boundingBox?.vertices![0], \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].boundingBox?.vertices![0].x, expectedBoundingBoxVerticeX, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].boundingBox?.vertices![0].y, expectedBoundingBoxVerticeY, \"value should be equal to expected value\")\n        \n        // paragraph\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0], \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages![0].languageCode, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages![0].languageCode, expectedLanguageCode, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages![0].confidence, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].property?.detectedLanguages![0].confidence, expectedConfidence, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].boundingBox, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].boundingBox?.vertices, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].boundingBox?.vertices![0], \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].boundingBox?.vertices![0].x, expectedParagraphBoundingBoxVerticeX, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].boundingBox?.vertices![0].y, expectedParagraphBoundingBoxVerticeY, \"value should be equal to expected value\")\n        \n        // words\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0], \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0], \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].property?.detectedLanguages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].property?.detectedLanguages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].property?.detectedLanguages![0].languageCode, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].property?.detectedLanguages![0].languageCode, expectedLanguageCode, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].boundingBox, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].boundingBox?.vertices, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].boundingBox?.vertices![0], \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].boundingBox?.vertices![0].x, expectedWordsBoundingBoxVerticeX, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].boundingBox?.vertices![0].y, expectedWordsBoundingBoxVerticeY, \"value should be equal to expected value\")\n       \n        // symbols\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].text, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].text, expectedSymbolText , \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].property, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].property?.detectedLanguages, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].property?.detectedLanguages![0], \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].property?.detectedLanguages![0].languageCode, \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].property?.detectedLanguages![0].languageCode, expectedLanguageCode, \"value should be equal to expected value\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].boundingBox, \"mock properties should not be nil\")\n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].boundingBox?.vertices, \"mock properties should not be nil\")\n        \n        XCTAssertNotNil(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].boundingBox?.vertices![0], \"mock properties should not be nil\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].boundingBox?.vertices![0].x, expectedSymbolsBoundingBoxVerticeX, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.info?.ocr?.advOcr?.data![0].fullTextAnnotation?.pages![0].blocks![0].paragraphs![0].words![0].symbols![0].boundingBox?.vertices![0].y, expectedSymbolsBoundingBoxVerticeY, \"value should be equal to expected value\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/OcrUploaderTests/UploaderOcrTests.swift",
    "content": "//\n//  UploaderOcrTests.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\nclass UploaderOcrTests: NetworkBaseTest {\n\n    // prevents redundant call to Cloudinary PAID OCR service. to allow OCR service testing - set environment variable \"CLD_TEST_ADDONS\" = \"ocr\".\n    override var testingAddonType: AddonType? { .ocr }\n    \n    // MARK: - upload\n    func test_upload_ocr_uploadShouldSucceed() throws {\n        \n        // Given\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .textImage\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        // When\n        let params = CLDUploadRequestParams()\n        params.setOcr(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNotNil(result?.info?.ocr, \"ocr param should not be nil\")\n    }\n    \n    // MARK: - explicit\n    func test_explicit_ocr_callShouldSucceed() throws {\n        \n        // Given\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .textImage\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        // When\n        let params = CLDUploadRequestParams()\n        params.setOcr(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        self.callForExplicit(publicId: result?.publicId)\n        \n        // Then\n        XCTAssertNil(error, \"upload error should be nil\")\n        XCTAssertNotNil(result, \"upload result should not be nil\")\n    }\n    \n    func callForExplicit(publicId: String?) {\n\n        guard let publicId = publicId else { return }\n        \n        // Given\n        let expectation = self.expectation(description: \"Explicit call with ocr should succeed\")\n        \n        var result: CLDExplicitResult?\n        var error: NSError?\n        \n        // When\n        let params = CLDExplicitRequestParams()\n        params.setOcr(true)\n        cloudinary!.createManagementApi().explicit(publicId, type: \"upload\", params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNil(error, \"explicit error should be nil\")\n        XCTAssertNotNil(result, \"explicit result should not be nil\")\n        XCTAssertNotNil(result?.info?.ocr, \"ocr param should not be nil\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/PreprocessUploaderTests/PreprocessUploaderTests.swift",
    "content": "//\n//  PreprocessUploaderTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\nclass PreprocessUploaderTests: NetworkBaseTest {\n\n    // MARK: - crop upload\n    func test_cropPreprocess_upload_croppedImageShouldBeUploaded() {\n        \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"must set api secret for this test\")\n        \n        // Given\n        let expectation = self.expectation(description: \"upload should succeed\")\n        \n        let file       = TestResourceType.borderCollie.url\n        \n        let cropWidth  = 47\n        let cropHeight = 43\n        let xPoint     = 200\n        let yPoint     = 100\n        \n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.crop(cropRect: CGRect(x: xPoint, y: yPoint, width: cropWidth, height: cropHeight)))\n        \n        // When\n        cloudinary!.createUploader().signedUpload(url: file, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertEqual(result?.width , cropWidth, \"returned image_width should be cropped\")\n        XCTAssertEqual(result?.height, cropHeight, \"returned image_height should be cropped\")\n    }\n    func test_cropPreprocess_uploadWidthOutOfBounds_croppedImageUploadShouldFail() {\n        \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"must set api secret for this test\")\n        \n        // Given\n        let expectation = self.expectation(description: \"upload should succeed\")\n        \n        let file       = TestResourceType.borderCollie.url\n        \n        let cropWidth  = 1147 // borderCollie image size 960 * 960\n        let cropHeight = 43\n        let xPoint     = 200\n        let yPoint     = 100\n        \n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.crop(cropRect: CGRect(x: xPoint, y: yPoint, width: cropWidth, height: cropHeight)))\n        \n        // When\n        cloudinary!.createUploader().signedUpload(url: file, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"result should be nil\")\n    }\n    func test_cropPreprocess_uploadHeightOutOfBounds_croppedImageUploadShouldFail() {\n        \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"must set api secret for this test\")\n        \n        // Given\n        let expectation = self.expectation(description: \"upload should succeed\")\n        \n        let file       = TestResourceType.borderCollie.url\n        \n        let cropWidth  = 47\n        let cropHeight = 1143 // borderCollie image size 960 * 960\n        let xPoint     = 200\n        let yPoint     = 100\n        \n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.crop(cropRect: CGRect(x: xPoint, y: yPoint, width: cropWidth, height: cropHeight)))\n        \n        // When\n        cloudinary!.createUploader().signedUpload(url: file, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"result should be nil\")\n    }\n    func test_cropPreprocess_uploadXOutOfBounds_croppedImageUploadShouldFail() {\n        \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"must set api secret for this test\")\n        \n        // Given\n        let expectation = self.expectation(description: \"upload should succeed\")\n        \n        let file       = TestResourceType.borderCollie.url\n        \n        let cropWidth  = 47\n        let cropHeight = 43\n        let xPoint     = -1\n        let yPoint     = 100\n        \n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.crop(cropRect: CGRect(x: xPoint, y: yPoint, width: cropWidth, height: cropHeight)))\n        \n        // When\n        cloudinary!.createUploader().signedUpload(url: file, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"result should be nil\")\n    }\n    func test_cropPreprocess_uploadYOutOfBounds_croppedImageUploadShouldFail() {\n        \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"must set api secret for this test\")\n        \n        // Given\n        let expectation = self.expectation(description: \"upload should succeed\")\n        \n        let file       = TestResourceType.borderCollie.url\n        \n        let cropWidth  = 47\n        let cropHeight = 43\n        let xPoint     = 200\n        let yPoint     = -1\n        \n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.crop(cropRect: CGRect(x: xPoint, y: yPoint, width: cropWidth, height: cropHeight)))\n        \n        // When\n        cloudinary!.createUploader().signedUpload(url: file, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"result should be nil\")\n    }\n    \n    // MARK: - crop download\n    func test_uploadPreprocess_cropDownloading_UploadedImageDataShouldBeEqualToCroppedImage() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"must set api secret for this test\")\n\n        // Given\n        let expectation = self.expectation(description: \"upload should succeed\")\n\n        let file       = TestResourceType.borderCollie.url\n        \n        let cropWidth  = 252\n        let cropHeight = 252\n        let xPoint     = 280\n        let yPoint     = 180\n        \n        var result  : CLDUploadResult?\n        var error   : NSError?\n        var publicId: String?\n        \n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.crop(cropRect: CGRect(x: xPoint, y: yPoint, width: cropWidth, height: cropHeight))).setEncoder(CLDPreprocessHelpers.customImageEncoder(format: .JPEG, quality: 90))\n        \n        // When\n        cloudinary!.createUploader().signedUpload(url: file, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            publicId = result?.publicId\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        \n        guard let pubId = publicId else {\n            XCTFail(\"publicId should not be nil at this point\")\n            return\n        }\n        \n        cropDownloading_uploadedImageDataShouldBeEqualToCroppedImage(publicId: pubId, testResourceType: .borderCollieCropped)\n    }\n    func cropDownloading_uploadedImageDataShouldBeEqualToCroppedImage(publicId: String, testResourceType: TestResourceType) {\n        \n        let expectation = self.expectation(description: \"download should succeed\")\n        \n        // Given\n        let localCroppedImageData = UIImage(data: testResourceType.data)?.pngData()\n        \n        var response: UIImage?\n        var error   : NSError?\n        \n        // When\n        let url = cloudinary!.createUrl().generate(publicId)\n        cloudinary!.createDownloader().fetchImage(url!).responseImage({ (responseImage, errorRes) in\n            response = responseImage\n            error    = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        let downloadedImageData = response?.pngData()\n\n        // Then\n        XCTAssertNotNil(response, \"response should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertEqual(downloadedImageData, localCroppedImageData, \"image downloaded after uploaded with crop preprocess, should be equal to expected cropped image\")\n    }\n    \n    // MARK: - rotate upload\n    func test_rotatePreprocess_upload45_rotatedImageShouldBeUploaded() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"must set api secret for this test\")\n\n        // Given\n        let expectation = self.expectation(description: \"upload should succeed\")\n\n        let file = TestResourceType.borderCollie.url\n        let inputDegree: Float = 45\n\n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let expectedSize = CGSize(width: 1357, height: 1357)\n\n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.rotate(degrees: inputDegree))\n\n        // When\n        cloudinary!.createUploader().signedUpload(url: file, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertEqual(result?.width , Int(expectedSize.width), \"returned image_width should be the rotated image's width\")\n        XCTAssertEqual(result?.height, Int(expectedSize.height), \"returned image_height should be the rotated image's height\")\n    }\n    func test_rotatePreprocess_upload90_rotatedImageShouldBeUploaded() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"must set api secret for this test\")\n\n        // Given\n        let expectation = self.expectation(description: \"upload should succeed\")\n\n        let file = TestResourceType.logo.url\n        let inputDegree: Float = 90\n\n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let expectedSize = CGSize(width: 51, height: 241)\n\n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.rotate(degrees: inputDegree))\n\n        // When\n        cloudinary!.createUploader().signedUpload(url: file, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertEqual(result?.width , Int(expectedSize.width), \"returned image_width should be the rotated image's width\")\n        XCTAssertEqual(result?.height, Int(expectedSize.height), \"returned image_height should be the rotated image's height\")\n    }\n\n    // MARK: - rotate download\n    func test_rotatePreprocess_rotateDownloadingPng_UploadedImageDataShouldBeEqualToRotatedImage() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"must set api secret for this test\")\n\n        // Given\n        let expectation = self.expectation(description: \"upload should succeed\")\n\n        let file = TestResourceType.borderCollie.url\n        let inputDegree: Float = 45\n\n        var result: CLDUploadResult?\n        var error: NSError?\n        var publicId: String?\n        \n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.rotate(degrees: inputDegree))\n\n        // When\n        cloudinary!.createUploader().signedUpload(url: file, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            publicId = result?.publicId\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n\n        guard let pubId = publicId else {\n            XCTFail(\"publicId should not be nil at this point\")\n            return\n        }\n\n        rotateDownloading_uploadedImageDataShouldBeEqualToRotatedImage(publicId: pubId, testResourceType: .borderCollieRotatedPng)\n    }\n    func test_rotatePreprocess_rotateDownloadingJpg_UploadedImageDataShouldBeEqualToRotatedImage() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"must set api secret for this test\")\n\n        // Given\n        let expectation = self.expectation(description: \"upload should succeed\")\n\n        let file = TestResourceType.borderCollie.url\n        let inputDegree: Float = 45\n\n        var result: CLDUploadResult?\n        var error: NSError?\n        var publicId: String?\n        \n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.rotate(degrees: inputDegree)).setEncoder(CLDPreprocessHelpers.customImageEncoder(format: .JPEG, quality: 100))\n\n        // When\n        cloudinary!.createUploader().signedUpload(url: file, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            publicId = result?.publicId\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n\n        guard let pubId = publicId else {\n            XCTFail(\"publicId should not be nil at this point\")\n            return\n        }\n\n        rotateDownloading_uploadedImageDataShouldBeEqualToRotatedImage(publicId: pubId, testResourceType: .borderCollieRotatedJpg)\n    }\n    func rotateDownloading_uploadedImageDataShouldBeEqualToRotatedImage(publicId: String, testResourceType: TestResourceType) {\n\n        let expectation = self.expectation(description: \"download should succeed\")\n\n        // Given\n        let localRotatedImageData = UIImage(data: testResourceType.data)\n\n        var response: UIImage?\n        var error   : NSError?\n\n        // When\n        let url = cloudinary!.createUrl().generate(publicId)\n        cloudinary!.createDownloader().fetchImage(url!).responseImage({ (responseImage, errorRes) in\n            response = responseImage\n            error    = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        let downloadedImageData = response?.pngData()\n\n        // Then\n        XCTAssertNotNil(response, \"response should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertEqual(response?.size, localRotatedImageData?.size, \"image downloaded after uploaded with rotate preprocess, should be equal to expected rotated image\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/QualityAnalysisUploaderTests/MockProviderQualityAnalysis.swift",
    "content": "//\n//  MockProviderQualityAnalysis.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\npublic class MockProviderQualityAnalysis: BaseMockProvider {\n    \n    // MARK: - json result\n    override class func jsonString() -> String {\n      \n        return \"{\\\"asset_id\\\":\\\"c9c2e940e1e5db90269f97af090b57fe\\\",\\\"public_id\\\":\\\"x7ldagsqc4wyyidbjahc\\\",\\\"version\\\":1602752171,\\\"version_id\\\":\\\"5f0199de7decc33210c6553c30e2ff57\\\",\\\"signature\\\":\\\"5d828d573c800ad8477b57f049add2b37eeff7cf\\\",\\\"width\\\":1144,\\\"height\\\":1048,\\\"format\\\":\\\"jpg\\\",\\\"resource_type\\\":\\\"image\\\",\\\"created_at\\\":\\\"2020-10-15T08:56:11Z\\\",\\\"tags\\\":[],\\\"pages\\\":1,\\\"bytes\\\":64893,\\\"type\\\":\\\"upload\\\",\\\"etag\\\":\\\"aa1a546faf1dad85ef49f6f6a2875602\\\",\\\"placeholder\\\":false,\\\"url\\\":\\\"http://res.cloudinary.com/ginidev/image/upload/v1602752171/x7ldagsqc4wyyidbjahc.jpg\\\",\\\"secure_url\\\":\\\"https://res.cloudinary.com/ginidev/image/upload/v1602752171/x7ldagsqc4wyyidbjahc.jpg\\\",\\\"access_mode\\\":\\\"public\\\",\\\"quality_analysis\\\":{\\\"jpeg_quality\\\":0.89,\\\"jpeg_chroma\\\":0.25,\\\"focus\\\":1.0,\\\"noise\\\":1.0,\\\"contrast\\\":0.99,\\\"exposure\\\":1.0,\\\"saturation\\\":1.0,\\\"lighting\\\":1.0,\\\"pixel_score\\\":0.9,\\\"color_score\\\":1.0,\\\"dct\\\":0.91,\\\"blockiness\\\":1.0,\\\"chroma_subsampling\\\":0.0,\\\"resolution\\\":0.58},\\\"quality_score\\\":0.76,\\\"original_filename\\\":\\\"textImage\\\"}\"\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/QualityAnalysisUploaderTests/ObjcQualityAnalysisExplicitResultParserTests.m",
    "content": "//\n//  QualityAnalysisExplicitResultParserTests.m\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"Cloudinary_Tests-Swift.h\"\n\n@interface ObjcQualityAnalysisExplicitResultParserTests : XCTestCase\n@property (nonatomic, strong, nullable) CLDExplicitResult* sut;\n@end\n\n@implementation ObjcQualityAnalysisExplicitResultParserTests\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n    self.sut = [MockProviderQualityAnalysis explicitResult];\n}\n\n- (void)tearDown {\n    [super tearDown];\n    self.sut = nil;\n}\n\n// MARK: - explicit result\n- (void)test_explicitResult_qualityAnalysisParsing_ShouldParseAsExpected {\n\n    // Given\n    NSNumber* expectedBlockiness        = @1.0;\n    NSNumber* expectedChromaSubsampling = @0.0;\n    NSNumber* expectedResolution        = @0.58;\n    NSNumber* expectedNoise             = @1.0;\n    NSNumber* expectedColorScore        = @1.0;\n    NSNumber* expectedJpegChroma        = @0.25;\n    NSNumber* expectedDct               = @0.91;\n    NSNumber* expectedJpegQuality       = @0.89;\n    NSNumber* expectedFocus             = @1.0;\n    NSNumber* expectedSaturation        = @1.0;\n    NSNumber* expectedContrast          = @0.99;\n    NSNumber* expectedExposure          = @1.0;\n    NSNumber* expectedLighting          = @1.0;\n    NSNumber* expectedPixelScore        = @0.9;\n    \n    // Then\n    XCTAssertNotNil(self.sut,                 \"explicit self.sut should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult, \"value should be equal to expected value\");\n    \n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.blockiness,        expectedBlockiness,        \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.chromaSubsampling, expectedChromaSubsampling, \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.resolution,        expectedResolution,        \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.noise,             expectedNoise,             \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.colorScore,        expectedColorScore,        \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.jpegChroma,        expectedJpegChroma,        \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.dct,               expectedDct,               \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.jpegQuality,       expectedJpegQuality,       \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.focus,             expectedFocus,             \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.saturation,        expectedSaturation,        \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.contrast,          expectedContrast,          \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.exposure,          expectedExposure,          \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.lighting,          expectedLighting,          \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.pixelScore,        expectedPixelScore,        \"value should be equal to expected value\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/QualityAnalysisUploaderTests/ObjcQualityAnalysisUploadResultParserTests.m",
    "content": "//\n//  ObjcQualityAnalysisUploadResultParserTests.m\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"Cloudinary_Tests-Swift.h\"\n\n@interface ObjcQualityAnalysisUploadResultParserTests : XCTestCase\n@property (nonatomic, strong, nullable) CLDUploadResult* sut;\n@end\n\n@implementation ObjcQualityAnalysisUploadResultParserTests\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n    self.sut = [MockProviderQualityAnalysis uploadResult];\n}\n\n- (void)tearDown {\n    [super tearDown];\n    self.sut = nil;\n}\n\n// MARK: - upload result\n- (void)test_uploadResult_qualityAnalysisParsing_ShouldParseAsExpected {\n\n    // Given\n    NSNumber* expectedBlockiness        = @1.0;\n    NSNumber* expectedChromaSubsampling = @0.0;\n    NSNumber* expectedResolution        = @0.58;\n    NSNumber* expectedNoise             = @1.0;\n    NSNumber* expectedColorScore        = @1.0;\n    NSNumber* expectedJpegChroma        = @0.25;\n    NSNumber* expectedDct               = @0.91;\n    NSNumber* expectedJpegQuality       = @0.89;\n    NSNumber* expectedFocus             = @1.0;\n    NSNumber* expectedSaturation        = @1.0;\n    NSNumber* expectedContrast          = @0.99;\n    NSNumber* expectedExposure          = @1.0;\n    NSNumber* expectedLighting          = @1.0;\n    NSNumber* expectedPixelScore        = @0.9;\n    \n    // Then\n    XCTAssertNotNil(self.sut,                 \"upload self.sut should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult, \"value should be equal to expected value\");\n    \n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.blockiness,        expectedBlockiness,        \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.chromaSubsampling, expectedChromaSubsampling, \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.resolution,        expectedResolution,        \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.noise,             expectedNoise,             \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.colorScore,        expectedColorScore,        \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.jpegChroma,        expectedJpegChroma,        \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.dct,               expectedDct,               \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.jpegQuality,       expectedJpegQuality,       \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.focus,             expectedFocus,             \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.saturation,        expectedSaturation,        \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.contrast,          expectedContrast,          \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.exposure,          expectedExposure,          \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.lighting,          expectedLighting,          \"value should be equal to expected value\");\n    XCTAssertEqualObjects(self.sut.qualityAnalysisResult.pixelScore,        expectedPixelScore,        \"value should be equal to expected value\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/QualityAnalysisUploaderTests/ObjcUploaderQualityAnalysisTests.m",
    "content": "//\n//  ObjcUploaderQualityAnalysisTests.m\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"Cloudinary_Tests-Swift.h\"\n#import \"NetworkBaseTestObjc.h\"\n\n@interface ObjcUploaderQualityAnalysisTests: NetworkBaseTestObjc\n@property (nonatomic, strong, nullable) __block CLDUploadResult* sut;\n@end\n\n@implementation ObjcUploaderQualityAnalysisTests\n\n// prevents redundant call to Cloudinary PAID Quality analysis service. to allow Quality analysis service testing - set to true.\n-(BOOL)allowQualityAnalysisCalls {\n    return [[[NSProcessInfo processInfo] arguments] containsObject:@\"TEST_QUALITY_ANALYSIS\"];\n}\n\n// MARK: - upload result\n- (void)test_upload_qualityAnalysisFalse_uploadShouldSucceedWithoutReturningQualityAnalysis {\n\n    XCTAssertNotNil(self.cloudinary.config.apiSecret, \"Must set api secret for this test\");\n    \n    // Given\n    XCTestExpectation *expectation = [self expectationWithDescription:@\"upload should succeed\"];\n    \n    TestResourceType resource = borderCollie;\n    NSURL* file = [self getUrlBy:resource];\n    \n    __block NSError* error;\n    \n    CLDUploadRequestParams* params = [[CLDUploadRequestParams alloc] init];\n    [params setQualityAnalysis:NO];\n    \n    // When\n    [[[self.cloudinary createUploader] signedUploadWithUrl:file params:params progress:nil completionHandler:nil] response:^(CLDUploadResult* resultRes, NSError* errorRes) {\n\n        self.sut = resultRes;\n        error    = errorRes;\n\n        [expectation fulfill];\n    }];\n    \n    [self waitForExpectationsWithTimeout:self.timeout handler:nil];\n    \n    // Then\n    XCTAssertNil(error, \"error should be nil\");\n    XCTAssertNotNil(self.sut, \"result should not be nil\");\n    XCTAssertNil   (self.sut.qualityAnalysisResult, \"quality analysis should be nil\");\n}\n- (void)test_upload_qualityAnalysisUnset_uploadShouldSucceedWithoutReturningQualityAnalysis {\n\n    XCTAssertNotNil(self.cloudinary.config.apiSecret, \"Must set api secret for this test\");\n    \n    // Given\n    XCTestExpectation *expectation = [self expectationWithDescription:@\"upload should succeed\"];\n    \n    TestResourceType resource = borderCollie;\n    NSURL* file = [self getUrlBy:resource];\n    \n    __block NSError* error;\n    \n    CLDUploadRequestParams* params = [[CLDUploadRequestParams alloc] init];\n    \n    // When\n    [[[self.cloudinary createUploader] signedUploadWithUrl:file params:params progress:nil completionHandler:nil] response:^(CLDUploadResult* resultRes, NSError* errorRes) {\n\n        self.sut = resultRes;\n        error    = errorRes;\n\n        [expectation fulfill];\n    }];\n    \n    [self waitForExpectationsWithTimeout:self.timeout handler:nil];\n    \n    // Then\n    XCTAssertNil(error, \"error should be nil\");\n    XCTAssertNotNil(self.sut, \"result should not be nil\");\n    XCTAssertNil   (self.sut.qualityAnalysisResult, \"quality analysis should be nil, defualt value should be false\");\n}\n- (void)test_upload_qualityAnalysis_uploadShouldReturnQualityAnalysis {\n\n    XCTSkipUnless([self allowQualityAnalysisCalls], \"prevents redundant call to Cloudinary PAID Quality Analysis service. to allow Quality Analysis service testing - set to true\");\n    \n    XCTAssertNotNil(self.cloudinary.config.apiSecret, \"must set api secret for this test\");\n    \n    // Given\n    XCTestExpectation *expectation = [self expectationWithDescription:@\"upload with quality should succeed\"];\n    \n    TestResourceType resource = borderCollie;\n    NSURL* file = [self getUrlBy:resource];\n    \n    __block NSError* error;\n    \n    CLDUploadRequestParams* params = [[CLDUploadRequestParams alloc] init];\n    [params setQualityAnalysis:YES];\n    \n    // When\n    [[[self.cloudinary createUploader] signedUploadWithUrl:file params:params progress:nil completionHandler:nil] response:^(CLDUploadResult* resultRes, NSError* errorRes) {\n\n        self.sut = resultRes;\n        error    = errorRes;\n\n        [expectation fulfill];\n    }];\n    \n    [self waitForExpectationsWithTimeout:self.timeout handler:nil];\n    \n    // Then\n    XCTAssertNil(error, \"error should be nil\");\n    XCTAssertNotNil(self.sut, \"result should not be nil\");\n    \n    XCTAssertNotNil(self.sut.qualityAnalysisResult, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.blockiness, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.chromaSubsampling, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.resolution, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.noise, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.colorScore, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.jpegChroma, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.dct, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.jpegQuality, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.focus, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.saturation, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.contrast, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.exposure, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.lighting, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(self.sut.qualityAnalysisResult.pixelScore, \"qualityAnalysis param should not be nil\");\n}\n\n// MARK: - explicit\n- (void)test_explicit_qualityAnalysis_callShouldReturnQualityAnalysis {\n\n    XCTSkipUnless([self allowQualityAnalysisCalls], \"prevents redundant call to Cloudinary PAID Quality Analysis service. to allow Quality Analysis service testing - set to true\");\n    \n    XCTAssertNotNil(self.cloudinary.config.apiSecret, \"must set api secret for this test\");\n    \n    // Given\n    XCTestExpectation *expectation = [self expectationWithDescription:@\"upload should succeed\"];\n    \n    TestResourceType resource = borderCollie;\n    NSURL* file = [self getUrlBy:resource];\n    \n    __block CLDUploadResult* uploadResult;\n    __block NSError* error;\n    \n    CLDUploadRequestParams* params = [[CLDUploadRequestParams alloc] init];\n    [params setQualityAnalysis:YES];\n    \n    // When\n    [[[self.cloudinary createUploader] signedUploadWithUrl:file params:params progress:nil completionHandler:nil] response:^(CLDUploadResult* resultRes, NSError* errorRes) {\n\n        uploadResult = resultRes;\n        error        = errorRes;\n\n        [expectation fulfill];\n    }];\n    \n    [self waitForExpectationsWithTimeout:self.timeout handler:nil];\n    \n    // Then\n    XCTAssertNil(error, \"error should be nil\");\n    XCTAssertNotNil(uploadResult, \"result should not be nil\");\n}\n- (void)callForExplicitWithPublicId:(NSString*) publicId {\n    \n    if(publicId == nil) {\n        return;\n    }\n    \n    // Given\n    XCTestExpectation *expectation =\n           [self expectationWithDescription:@\"explicit call with quality should succeed\"];\n    \n    __block CLDExplicitResult* result;\n    __block NSError* error;\n    \n    CLDExplicitRequestParams* params = [[CLDExplicitRequestParams alloc] init];\n    [params setQualityAnalysis:YES];\n    \n    // When\n    [[[self.cloudinary createManagementApi] explicitPublicId:publicId stringType:@\"upload\" params:params completionHandler:nil] response:^(CLDExplicitResult* resultRes, NSError* errorRes) {\n        \n        result = resultRes;\n        error  = errorRes;\n\n        [expectation fulfill];\n    }];\n    \n    [self waitForExpectationsWithTimeout:self.timeout handler:nil];\n    \n    // Then\n    XCTAssertNil(error, \"error should be nil\");\n    XCTAssertNotNil(result, \"result should not be nil\");\n    \n    XCTAssertNotNil(result.qualityAnalysisResult, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.blockiness, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.chromaSubsampling, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.resolution, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.noise, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.colorScore, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.jpegChroma, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.dct, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.jpegQuality, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.focus, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.saturation, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.contrast, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.exposure, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.lighting, \"qualityAnalysis param should not be nil\");\n    XCTAssertNotNil(result.qualityAnalysisResult.pixelScore, \"qualityAnalysis param should not be nil\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/QualityAnalysisUploaderTests/QualityAnalysisExplicitResultParserTests.swift",
    "content": "//\n//  QualityAnalysisExplicitResultParserTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\n// QualityAnalysisExplicitResultParserTests created to reduce server calls to Cloudinary PAID Quality analysis service\nclass QualityAnalysisExplicitResultParserTests: NetworkBaseTest {\n\n    var sut : CLDExplicitResult!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = MockProviderQualityAnalysis.explicitResult\n    }\n    override func tearDown() {\n        super.tearDown()\n        sut = nil\n    }\n    \n    // MARK: - explicit result\n    func test_explicitResult_qualityAnalysisParsing_ShouldParseAsExpected() {\n\n        // Given\n        let expectedBlockiness        = NSNumber(value: 1.0)\n        let expectedChromaSubsampling = NSNumber(value: 0.0)\n        let expectedResolution        = NSNumber(value: 0.58)\n        let expectedNoise             = NSNumber(value: 1.0)\n        let expectedColorScore        = NSNumber(value: 1.0)\n        let expectedJpegChroma        = NSNumber(value: 0.25)\n        let expectedDct               = NSNumber(value: 0.91)\n        let expectedJpegQuality       = NSNumber(value: 0.89)\n        let expectedFocus             = NSNumber(value: 1.0)\n        let expectedSaturation        = NSNumber(value: 1.0)\n        let expectedContrast          = NSNumber(value: 0.99)\n        let expectedExposure          = NSNumber(value: 1.0)\n        let expectedLighting          = NSNumber(value: 1.0)\n        let expectedPixelScore        = NSNumber(value: 0.9)\n        \n        // Then\n        XCTAssertNotNil(sut,                 \"explicit sut should not be nil\")\n        XCTAssertNotNil(sut.qualityAnalysisResult, \"value should be equal to expected value\")\n        \n        XCTAssertEqual(sut.qualityAnalysisResult?.blockiness,        expectedBlockiness,        \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.chromaSubsampling, expectedChromaSubsampling, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.resolution,        expectedResolution,        \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.noise,             expectedNoise,             \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.colorScore,        expectedColorScore,        \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.jpegChroma,        expectedJpegChroma,        \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.dct,               expectedDct,               \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.jpegQuality,       expectedJpegQuality,       \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.focus,             expectedFocus,             \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.saturation,        expectedSaturation,        \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.contrast,          expectedContrast,          \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.exposure,          expectedExposure,          \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.lighting,          expectedLighting,          \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.pixelScore,        expectedPixelScore,        \"value should be equal to expected value\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/QualityAnalysisUploaderTests/QualityAnalysisUploadResultParserTests.swift",
    "content": "//\n//  QualityAnalysisUploadResultParserTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\n// QualityAnalysisUploadResultParserTests created to reduce server calls to Cloudinary PAID Quality analysis service\nclass QualityAnalysisUploadResultParserTests: NetworkBaseTest {\n\n    var sut : CLDUploadResult!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = MockProviderQualityAnalysis.uploadResult\n    }\n    override func tearDown() {\n        super.tearDown()\n        sut = nil\n    }\n    \n    // MARK: - upload result\n    func test_uploadResult_qualityAnalysisParsing_ShouldParseAsExpected() {\n\n        // Given\n        let expectedBlockiness        = NSNumber(value: 1.0)\n        let expectedChromaSubsampling = NSNumber(value: 0.0)\n        let expectedResolution        = NSNumber(value: 0.58)\n        let expectedNoise             = NSNumber(value: 1.0)\n        let expectedColorScore        = NSNumber(value: 1.0)\n        let expectedJpegChroma        = NSNumber(value: 0.25)\n        let expectedDct               = NSNumber(value: 0.91)\n        let expectedJpegQuality       = NSNumber(value: 0.89)\n        let expectedFocus             = NSNumber(value: 1.0)\n        let expectedSaturation        = NSNumber(value: 1.0)\n        let expectedContrast          = NSNumber(value: 0.99)\n        let expectedExposure          = NSNumber(value: 1.0)\n        let expectedLighting          = NSNumber(value: 1.0)\n        let expectedPixelScore        = NSNumber(value: 0.9)\n        \n        \n        // Then\n        XCTAssertNotNil(sut,                 \"upload sut should not be nil\")\n        XCTAssertNotNil(sut.qualityAnalysisResult, \"value should be equal to expected value\")\n        \n        XCTAssertEqual(sut.qualityAnalysisResult?.blockiness,        expectedBlockiness,        \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.chromaSubsampling, expectedChromaSubsampling, \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.resolution,        expectedResolution,        \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.noise,             expectedNoise,             \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.colorScore,        expectedColorScore,        \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.jpegChroma,        expectedJpegChroma,        \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.dct,               expectedDct,               \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.jpegQuality,       expectedJpegQuality,       \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.focus,             expectedFocus,             \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.saturation,        expectedSaturation,        \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.contrast,          expectedContrast,          \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.exposure,          expectedExposure,          \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.lighting,          expectedLighting,          \"value should be equal to expected value\")\n        XCTAssertEqual(sut.qualityAnalysisResult?.pixelScore,        expectedPixelScore,        \"value should be equal to expected value\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/QualityAnalysisUploaderTests/UploaderQualityAnalysisTests.swift",
    "content": "//\n//  UploaderQualityAnalysisTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\nclass UploaderQualityAnalysisTests: NetworkBaseTest {\n\n    var sut: CLDUploadResult?\n    \n    // prevents redundant call to Cloudinary PAID Quality analysis service. to allow Quality analysis service testing - set to true.\n    var allowQualityAnalysisCalls: Bool {\n        return ProcessInfo.processInfo.arguments.contains(\"TEST_QUALITY_ANALYSIS\")\n    }\n    \n    // MARK: - upload\n    func test_upload_qualityAnalysisFalse_uploadShouldSucceedWithoutReturningQualityAnalysis() {\n\n        // Given\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .textImage\n        let file = resource.url\n        var error: NSError?\n\n        // When\n        let params = CLDUploadRequestParams()\n        params.setQualityAnalysis(false)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            \n            self.sut = resultRes\n            error    = errorRes\n            \n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(sut, \"result should not be nil\")\n        XCTAssertNil   (sut?.qualityAnalysisResult, \"qualityAnalysis param should be nil\")\n    }\n    func test_upload_qualityAnalysisUnset_uploadShouldSucceedWithoutReturningQualityAnalysis() {\n\n        // Given\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .textImage\n        let file = resource.url\n        var error: NSError?\n\n        // When\n        let params = CLDUploadRequestParams()\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            \n            self.sut = resultRes\n            error    = errorRes\n            \n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(sut, \"result should not be nil\")\n        XCTAssertNil   (sut?.qualityAnalysisResult, \"qualityAnalysis param should be nil, defualt value should be false\")\n    }\n    func test_upload_qualityAnalysis_uploadShouldReturnQualityAnalysis() throws {\n\n        try XCTSkipUnless(allowQualityAnalysisCalls, \"prevents redundant call to Cloudinary PAID Quality Analysis service. to allow Quality Analysis service testing - set to true\")\n        \n        // Given\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .textImage\n        let file = resource.url\n        var error: NSError?\n\n        // When\n        let params = CLDUploadRequestParams()\n        params.setQualityAnalysis(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            \n            self.sut = resultRes\n            error    = errorRes\n            \n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Then\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(sut, \"result should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.blockiness, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.chromaSubsampling, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.resolution, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.noise, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.colorScore, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.jpegChroma, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.dct, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.jpegQuality, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.focus, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.saturation, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.contrast, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.exposure, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.lighting, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(sut?.qualityAnalysisResult?.pixelScore, \"qualityAnalysis param should not be nil\")\n    }\n    \n    // MARK: - explicit\n    func test_explicit_qualityAnalysis_callShouldReturnQualityAnalysis() throws {\n\n        try XCTSkipUnless(allowQualityAnalysisCalls, \"prevents redundant call to Cloudinary PAID Quality Analysis service. to allow Quality Analysis service testing - set to true\")\n        \n        // Given\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .textImage\n        let file = resource.url\n        var error: NSError?\n\n        // When\n        let params = CLDUploadRequestParams()\n        params.setQualityAnalysis(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            \n            self.sut = resultRes\n            error    = errorRes\n            \n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        self.callForExplicit(publicId: sut?.publicId)\n        \n        // Then\n        XCTAssertNil(error, \"upload error should be nil\")\n        XCTAssertNotNil(sut, \"upload result should not be nil\")\n    }\n    \n    func callForExplicit(publicId: String?) {\n\n        guard let publicId = publicId else { return }\n        \n        // Given\n        let expectation = self.expectation(description: \"Explicit call with qualityAnalysis should succeed\")\n        \n        var explicitSut: CLDExplicitResult?\n        var error : NSError?\n        \n        // When\n        let params = CLDExplicitRequestParams()\n        params.setQualityAnalysis(true)\n        cloudinary!.createManagementApi().explicit(publicId, type: \"upload\", params: params).response({ (resultRes, errorRes) in\n            \n            explicitSut = resultRes\n            error       = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        // Then\n        XCTAssertNil(error, \"explicit error should be nil\")\n        XCTAssertNotNil(explicitSut, \"explicit result should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.blockiness, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.chromaSubsampling, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.resolution, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.noise, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.colorScore, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.jpegChroma, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.dct, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.jpegQuality, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.focus, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.saturation, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.contrast, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.exposure, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.lighting, \"qualityAnalysis param should not be nil\")\n        XCTAssertNotNil(explicitSut?.qualityAnalysisResult?.pixelScore, \"qualityAnalysis param should not be nil\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/NetworkTests/UploaderTests/UploaderTests.swift",
    "content": "//\n//  UploaderTests.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n@testable import Cloudinary\n\nclass UploaderTests: NetworkBaseTest {\n\n    // MARK: - Tests\n\n    func testUploadImageData() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let data = TestResourceType.borderCollie.data\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setColors(true)\n        cloudinary!.createUploader().signedUpload(data: data, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testUploadMediaMetadata() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let data = TestResourceType.borderCollie.data\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setMediaMetadata(true)\n        cloudinary!.createUploader().signedUpload(data: data, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNotNil(result?.getParam(.metadata), \"metadata should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testUploadRespectTimeoutFromConfiguration() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"upload should fail\")\n        let data = TestResourceType.borderCollie.data\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setColors(true)\n        cloudinaryInsufficientTimeout!.createUploader().signedUpload(data: data, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        var actualResult = String()\n\n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n\n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n\n    func testUploadRespectTimeoutFromParameters() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectedResult = \"-1001\"\n        let expectation = self.expectation(description: \"upload should fail\")\n        let data = TestResourceType.borderCollie.data\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setColors(true)\n        params.setTimeout(from: cloudinaryInsufficientTimeout!.config)\n        cloudinaryInsufficientTimeout!.createUploader().signedUpload(data: data, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        var actualResult = String()\n\n        if let error = error {\n            actualResult = String((error as NSError).code)\n        }\n\n        XCTAssertNotNil(error, \"error should not be nil\")\n        XCTAssertNil(result, \"response should be nil\")\n        XCTAssertEqual(actualResult, expectedResult, \"error should occur due to timeout\")\n    }\n    \n    func testUploadPNGImageData() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let data = TestResourceType.logo.data\n        \n        // Load the image into memory to decompress it, this will give us the real size of the image.\n        let imageSize = UIImage(data: data)?.pngData()?.count\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setResourceType(.image)\n        let chain = CLDImagePreprocessChain().setEncoder(CLDPreprocessHelpers.customImageEncoder(format: EncodingFormat.PNG, quality: 100))\n        \n        cloudinary!.createUploader().signedUpload(data: data, params: params, preprocessChain: chain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertEqual(imageSize, Int(result!.length!))\n    }\n    \n    func testUploadPNGImageDataFromMemory() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let pngImageDataLoadedToMemory = UIImage(data: TestResourceType.logo.data)!.pngData()!\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setResourceType(.image)\n        let chain = CLDImagePreprocessChain().setEncoder(CLDPreprocessHelpers.customImageEncoder(format: EncodingFormat.PNG, quality: 100))\n        \n        cloudinary!.createUploader().signedUpload(data: pngImageDataLoadedToMemory, params: params, preprocessChain: chain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertEqual(pngImageDataLoadedToMemory.count, Int(result!.length!))\n    }\n    \n    func testUploadPNGImageFile() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let url = TestResourceType.logo.url\n\n        // Load the image into memory to decompress it, this will give us the real size of the image.\n        let imageSize = UIImage(contentsOfFile: url.relativePath)?.pngData()?.count\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setResourceType(.image)\n        let chain = CLDImagePreprocessChain().setEncoder(CLDPreprocessHelpers.customImageEncoder(format: EncodingFormat.PNG, quality: 100))\n        \n        cloudinary!.createUploader().signedUpload(url: url, params: params, preprocessChain: chain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertEqual(imageSize, Int(result!.length!))\n    }\n    \n    func testUploadPNGImageFileWithPreprocess() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let file = TestResourceType.logo.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let preprocessChain = CLDImagePreprocessChain()\n            .addStep(CLDPreprocessHelpers.limit(width: 50, height: 50))\n            .setEncoder(CLDPreprocessHelpers.customImageEncoder(format: EncodingFormat.PNG, quality: 100))\n        let params = CLDUploadRequestParams()\n        params.setColors(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result!.width, \"width should not be nil\")\n        XCTAssertNotNil(result!.height, \"height should not be nil\")\n        // The image \"logo\" is not a square, setting maximum width and height to 50 will match its aspect ratio but still should be less then or equal to 50.\n        XCTAssertTrue(result!.width! <= 50, \"Width must be less then 50\")\n        XCTAssertTrue(result!.height! <= 50, \"Height must be less then 50\")\n    }\n\n    func testUploadImageFile() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let file = TestResourceType.borderCollie.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setColors(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testUploadFolderDecoupling() throws {\n\n        try XCTSkipUnless(NetworkTestUtils.skipFolderDecouplingTest(), \"prevents redundant call to Cloudinary PAID Folder Decoupling service. to allow Folder Decoupling service testing - set to true\")\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed and return the params sent\")\n        let file = TestResourceType.borderCollie.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n\n        params.setPublicIdPrefix(\"public_id_prefix\")\n        params.setAssetFolder(\"asset_folder\")\n        params.setDisplayName(\"display_name\")\n        params.setUseFilenameAsDisplayName(true)\n        params.setFolder(\"folder/test\")\n\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result?.assetFolder, \"result should not be nil\")\n        XCTAssertNotNil(result?.displayName, \"result should not be nil\")\n\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testUploadImageFileWithPreprocess() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let file = TestResourceType.borderCollie.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.limit(width: 500, height: 500))\n        let params = CLDUploadRequestParams()\n        params.setColors(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertEqual(result?.width, 500)\n        XCTAssertEqual(result?.height, 500)\n    }\n\n    func testUploadWithPreprocessValidator() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should fail\")\n        let file = TestResourceType.logo.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let preprocessChain = CLDImagePreprocessChain().addStep(CLDPreprocessHelpers.dimensionsValidator(minWidth: 500, maxWidth: 1500, minHeight: 500, maxHeight: 1500))\n        let params = CLDUploadRequestParams()\n        params.setColors(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params, preprocessChain: preprocessChain).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNil(result, \"result should be nil\")\n        XCTAssertNotNil(error, \"error should not be nil\")\n    }\n\n    func testUploadLargeErrors() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        var expectation = self.expectation(description: \"Chunk size under 5MB should fail\")\n        let file = TestResourceType.dog.url\n        var requestError: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setResourceType(CLDUrlResourceType.video)\n        // chunk size is too small:\n        cloudinary!.createUploader().signedUploadLarge(url: file, params: params, chunkSize: 3 * 1024 * 1024, progress: nil).response({ (resultRes, errorRes) in\n            requestError = errorRes\n            expectation.fulfill()\n        })\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        expectation = self.expectation(description: \"Uploading non-existing file should fail\")\n        cloudinary!.createUploader().signedUploadLarge(url: URL(fileURLWithPath: \"non/existing/file\"), params: params, chunkSize: 10 * 1024 * 1024, progress: nil).response({ (resultRes, errorRes) in\n            requestError = errorRes\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(requestError, \"Error should not be nil\")\n    }\n\n    func testUploadVideoData() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let data = TestResourceType.dog.data\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams().setColors(true)\n        params.setResourceType(.video)\n        cloudinary!.createUploader().signedUpload(data: data, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: 60.0, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testUploadAccessControlParams() {\n\n        let formatter = DateFormatter()\n        formatter.calendar = Calendar(identifier: .iso8601)\n        formatter.locale = Locale(identifier: \"en_US_POSIX\")\n        formatter.dateFormat = \"yyyy-MM-dd HH:mm:ss Z\"\n\n        let aclToken = CLDAccessControlRule.token()\n        let start = formatter.date(from: \"2019-02-22 16:20:57 +0200\")!\n        let end = formatter.date(from: \"2019-03-22 00:00:00 +0200\")!\n        let acl = CLDAccessControlRule.anonymous(start: start, end: end)\n\n        let aclString = \"{\\\"access_type\\\":\\\"anonymous\\\",\\\"start\\\":\\\"2019-02-22 16:20:57 +0200\\\",\\\"end\\\":\\\"2019-03-22 00:00 +0200\\\"}\"\n\n        var params = CLDUploadRequestParams().setAccessControl([aclToken])\n        XCTAssertEqual(params.accessControl, \"[{\\\"access_type\\\":\\\"token\\\"}]\")\n\n        params = CLDUploadRequestParams().setAccessControl([acl])\n        XCTAssertNotNil(params.accessControl)\n\n        params = CLDUploadRequestParams().setAccessControl(aclString)\n        XCTAssertEqual(params.accessControl!, aclString)\n    }\n\n    func testUploadWithAccessControl() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let formatter = DateFormatter()\n        formatter.calendar = Calendar(identifier: .iso8601)\n        formatter.locale = Locale(identifier: \"en_US_POSIX\")\n        formatter.dateFormat = \"yyyy-MM-dd HH:mm:ss Z\"\n        let start = formatter.date(from: \"2019-02-22 16:20:57 +0200\")!\n        let end = formatter.date(from: \"2019-03-22 00:00:00 +0200\")!\n\n        let anonStartEnd = CLDAccessControlRule.anonymous(start: start, end: end)\n        let anonStart = CLDAccessControlRule.anonymous(start: start)\n        let anonEnd = CLDAccessControlRule.anonymous(end: end)\n        let token = CLDAccessControlRule.token()\n\n        uploadAndCompare(accessControl: [anonStartEnd])\n        uploadAndCompare(accessControl: [anonStart])\n        uploadAndCompare(accessControl: [anonEnd])\n        uploadAndCompare(accessControl: [token])\n        uploadAndCompare(accessControl: [anonStart, token])\n        uploadAndCompare(accessControl: [anonStartEnd, token])\n        uploadAndCompare(accessControl: [token, anonEnd])\n    }\n\n    fileprivate func uploadAndCompare(accessControl: [CLDAccessControlRule]) {\n        let file = TestResourceType.borderCollie.url\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n\n        let params = CLDUploadRequestParams().setAccessControl(accessControl)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: 30.0, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n\n        let returnedAcl = (result?.accessControl)!\n\n        for index in 0..<returnedAcl.count {\n            XCTAssertTrue(returnedAcl[index] == accessControl[index], \"Returned access control should be equal to the requested access control\")\n        }\n    }\n\n    func testUploadVideoFile() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let file = TestResourceType.dog.url\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams().setColors(true)\n        params.setResourceType(.video)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: 60.0, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testUploadImageDataUsingSignature() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let data = TestResourceType.borderCollie.data\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n\n        let timestamp = Int(Date().timeIntervalSince1970)\n        let signature = cloudinarySignParamsUsingSecret([\"timestamp\": String(describing: timestamp)], cloudinaryApiSecret: cloudinary!.config.apiSecret!)\n\n        let params = CLDUploadRequestParams()\n        params.setSignature(CLDSignature(signature: signature, timestamp: NSNumber(value: timestamp)))\n        cloudinary!.createUploader().signedUpload(data: data, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testUnsignedUploadImageFile() {\n\n        let prefix = cloudinary!.config.apiSecret != nil ? \"\\(cloudinary!.config.apiKey!):\\(cloudinary!.config.apiSecret!)\" : cloudinary!.config.apiKey!\n        let uploadPresetUrl = \"https://\\(prefix)@api.cloudinary.com/v1_1/\\(cloudinary!.config.cloudName!)/upload_presets\"\n        let presetName = \"ios_unsigned_upload\"\n\n        var options = [String: AnyObject]()\n        options[\"api_key\"] = cloudinary?.config.apiKey as AnyObject\n        options[\"cloud_name\"] = cloudinary?.config.cloudName as AnyObject\n\n        let config = CLDConfiguration(options: options)\n        let cloudinaryNoSecret = CLDCloudinary(configuration: config!, sessionConfiguration: URLSessionConfiguration.default)\n\n        XCTAssertNil(cloudinaryNoSecret.config.apiSecret, \"api secret should not be set to test unsigned upload\")\n\n        createUploadPresetIfNeeded(uploadPresetUrl, presetName: presetName)\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let file = TestResourceType.borderCollie.url\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        cloudinaryNoSecret.createUploader().upload(url: file, uploadPreset: presetName, params: CLDUploadRequestParams()).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            expectation.fulfill()\n        })\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n\n        if let\n           pubId = result?.publicId,\n           let version = result?.version,\n           let sig = result?.signature {\n            let toSign = [\"public_id\": pubId, \"version\": version]\n            let expectedSignature = cloudinarySignParamsUsingSecret(toSign, cloudinaryApiSecret: (cloudinary!.config.apiSecret)!)\n            XCTAssertEqual(sig, expectedSignature)\n        } else {\n            XCTFail(\"Need to receive public_id, version and signature in the response\")\n        }\n    }\n\n    func testSignatureWithEscapingCharacters() {\n        let cloudName = \"dn6ot3ged\"\n                let apiSecret = \"hdcixPpR2iKERPwqvH6sHdK9cyac\"\n\n                let paramsWithAmpersand: [String: Any] = [\n                    \"cloud_name\": cloudName,\n                    \"timestamp\": 1568810420,\n                    \"notification_url\": \"https://fake.com/callback?a=1&tags=hello,world\"\n                ]\n\n                let signatureWithAmpersand = cloudinarySignParamsUsingSecret(paramsWithAmpersand, cloudinaryApiSecret: apiSecret)\n\n                let paramsSmuggled: [String: Any] = [\n                    \"cloud_name\": cloudName,\n                    \"timestamp\": 1568810420,\n                    \"notification_url\": \"https://fake.com/callback?a=1\",\n                    \"tags\": \"hello,world\"\n                ]\n\n                let signatureSmuggled = cloudinarySignParamsUsingSecret(paramsSmuggled, cloudinaryApiSecret: apiSecret)\n\n                // Assert that smuggling changes the signature\n                XCTAssertNotEqual(signatureWithAmpersand, signatureSmuggled,\n                                  \"Signatures should be different to prevent parameter smuggling\")\n\n                // Assert expected signatures\n                let expectedSignature = \"4fdf465dd89451cc1ed8ec5b3e314e8a51695704\"\n                XCTAssertEqual(signatureWithAmpersand, expectedSignature)\n\n                let expectedSmuggledSignature = \"7b4e3a539ff1fa6e6700c41b3a2ee77586a025f9\"\n                XCTAssertEqual(signatureSmuggled, expectedSmuggledSignature)\n\n                let versionOneSignature = cloudinarySignParamsUsingSecret(paramsSmuggled, cloudinaryApiSecret: apiSecret, signatureVersion: 1)\n                XCTAssertEqual(signatureSmuggled, versionOneSignature)\n    }\n\n\n    func testUploadRemoteUrl() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        cloudinary!.createUploader().signedUpload(url: URL(string: \"http://cloudinary.com/images/old_logo.png\")!, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n\n    }\n    \n    func testUploadLargeRemoteUrl() {\n        \n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        \n        let expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let params = CLDUploadRequestParams()\n        cloudinary!.createUploader().signedUploadLarge(url: URL(string: \"http://cloudinary.com/images/old_logo.png\")!, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        \n    }\n\n\n    func testUseFilename() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let filename = resource.fileName\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setUseFilename(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertTrue(isUsedFilename(filename: filename, publicId: result?.publicId))\n    }\n    \n    func isUsedFilename(filename: String, publicId: String?)-> Bool {\n        var matches = 0\n        if let publicId = publicId {\n            let regex = try! NSRegularExpression(pattern: \"\\(filename)_[a-z0-9]{6}\", options: NSRegularExpression.Options(rawValue: 0))\n            matches = regex.numberOfMatches(in: publicId, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, publicId.count))\n        }\n        \n        return matches == 1\n    }\n\n    func testUniqueFilename() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let filename = resource.fileName\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setUseFilename(true).setUniqueFilename(false)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n\n        XCTAssertEqual(result?.publicId ?? \"\", filename)\n    }\n\n    func testUploadAsync() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams().setAsync(true)\n\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n\n        let status = result?.resultJson[\"status\"] as? String\n        XCTAssertEqual(status, \"pending\")\n    }\n    \n    func testUploadLargeWithSignature(){\n        let expectation = self.expectation(description: \"Signed upload large should succeed\")\n        let timestamp = Int(Date().timeIntervalSince1970)\n        let signature = cloudinarySignParamsUsingSecret([\"timestamp\" : String(describing: timestamp)], cloudinaryApiSecret: (cloudinary?.config.apiSecret)!)\n        \n        let params = CLDUploadRequestParams().setResourceType(CLDUrlResourceType.video).setSignature(CLDSignature(signature: signature, timestamp: NSNumber(value: timestamp)))\n        let resource: TestResourceType = .dog\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        cloudinaryNoSecret.createUploader().signedUploadLarge(url: file, params: params as! CLDUploadRequestParams, chunkSize: 6 * 1024 * 1024)\n            .response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testEager() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        let trans = CLDEagerTransformation().setCrop(.crop).setWidth(2.0).setFormat(\"png\")\n        let trans2 = CLDEagerTransformation().setCrop(.crop).setWidth(2.0).setFormat(\"gif\")\n        params.setEager([trans, trans2])\n\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertTrue((result?.eager?[0].url?.hasSuffix(\"png\")) ?? false)\n        XCTAssertTrue((result?.eager?[1].url?.hasSuffix(\"gif\")) ?? false)\n    }\n\n    func testHeaders() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setHeaders([\"Link\": \"1\"])\n        params.setContext([\"caption\": \"My Logo\"])\n        cloudinary?.setExtraHeaderes([\"Test\": \"Test\"])\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testExtraHeaders() {\n        let extraHeaders = [\"Test\": \"Test\"]\n        let testCloudinary = CLDCloudinary(configuration: cloudinary!.config)\n        testCloudinary.setExtraHeaderes(extraHeaders)\n        let networkCoordinator = TestableCloudinary.getNetworkCoordinator(from: testCloudinary) as! CLDNetworkCoordinator\n        XCTAssertEqual(networkCoordinator.getExtraHeaders(), extraHeaders)\n    }\n\n    func testFaceCoordinates() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        let coordinate = CLDCoordinate(rect: CGRect(x: 10, y: 10, width: 100, height: 15000))\n        params.setFaceCoordinates([coordinate])\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        let resultCoords = (result!.coordinates!.faces as! NSArray)[0] as! NSArray\n        XCTAssertEqual(resultCoords[0] as! Float, 10)\n        XCTAssertEqual(resultCoords[1] as! Float, 10)\n        XCTAssertEqual(resultCoords[2] as! Float, 100)\n        XCTAssertEqual(resultCoords[3] as! Float, Float(result!.height!))\n    }\n\n    func testCustomCoordinates() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        let coordinate = CLDCoordinate(rect: CGRect(x: 10, y: 10, width: 100, height: 100))\n        params.setCustomCoordinates([coordinate])\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testResponsiveBreakpoints() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        \n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let params = CLDUploadRequestParams()\n        let breakpoints = CLDResponsiveBreakpoints(createDerived: true).setBytesStep(1000).setFormat(\"webp\").setTransformations(CLDTransformation().setAngle(10))\n        params.setResponsiveBreakpoints([breakpoints])\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        XCTAssertNotNil(result?.responsiveBreakpoints?[0].breakpoints?[0].url, \"responsive breakpoints url cannot be nil\")\n        XCTAssertTrue(result!.responsiveBreakpoints![0].breakpoints![0].url!.hasSuffix(\"webp\"), \"responsive breakpoints url has to end with the right format (webp)\")\n        XCTAssertNotNil(result?.responsiveBreakpoints?[0].transformation)\n        XCTAssertTrue(result!.responsiveBreakpoints![0].transformation!.contains(\"a_10\"))\n    }\n    \n    func testContext() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        var expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        let customContext = [\"caption\": \"some cäption\", \"alt\": \"alternativè\"]\n        params.setContext(customContext)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            if let error = error {\n                print(error)\n            }\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        if let context = result!.context {\n            if let custom = context[\"custom\"] {\n                XCTAssertTrue(NSDictionary(dictionary: custom).isEqual(to: customContext))\n            } else {\n                XCTFail(\"Context should have a 'custom' key\")\n            }\n        } else {\n            XCTFail(\"Result should include a 'context' key\")\n        }\n\n        expectation = self.expectation(description: \"Explicit should succeed\")\n        let differentContext = [\"caption\": \"different = caption\", \"alt2\": \"alt|alternative alternative\"]\n\n        let exParams: CLDExplicitRequestParams? = CLDExplicitRequestParams().setType(.upload).setContext(differentContext)\n        cloudinary!.createManagementApi().explicit(result!.publicId!, type: .upload, params: exParams).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        if let context = result!.context {\n            if let custom = context[\"custom\"] {\n                XCTAssertTrue(NSDictionary(dictionary: custom).isEqual(to: differentContext))\n            } else {\n                XCTFail(\"Context should have a 'custom' key\")\n            }\n        } else {\n            XCTFail(\"Result should include a 'context' key\")\n        }\n    }\n    \n    func testQualityAnalysis() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        \n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let params = CLDUploadRequestParams()\n        params.setQualityAnalysis(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        \n        XCTAssertNotNil(result?.qualityAnalysisResult, \"quality analysis field in upload result should not be nil\")\n    }\n    \n    func test_upload_NoApiKeyFail() {\n        \n        // Given\n        XCTAssertNotNil(cloudinary!.config.apiKey, \"Must set api key for this test\")\n        \n        let expectation = self.expectation(description: \"Upload should fail for not specifing an api key in config and not passing it as argument\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let configWithEmptyApiKey = CLDConfiguration(cloudName: cloudinary!.config.cloudName,\n                                                     apiKey: \"\",\n                                                     apiSecret: cloudinary!.config.apiSecret,\n                                                     secure: true)\n        let cloudinaryWithNoKey = CLDCloudinary(configuration: configWithEmptyApiKey, sessionConfiguration: .default)\n\n        // When\n        cloudinaryWithNoKey.createUploader().signedUpload(url: file, params: CLDUploadRequestParams()).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Expect\n        XCTAssertNil(result, \"result should be nil\")\n        XCTAssertNotNil(error, \"error should not be nil\")\n        \n        XCTAssertEqual(400, error!.code)\n        XCTAssertEqual(\"Missing required parameter - api_key\", error!.userInfo[\"message\"] as! String, \"Api key should be unassigned\")\n    }\n    \n    func test_upload_ApiKeyAsArgument() {\n        \n        // Given\n        \n        XCTAssertNotNil(cloudinary!.config.apiKey, \"Must set api key for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed with the key passed as an argument\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let cloudName = cloudinary!.config.cloudName!\n        let apiKey    = \"\"\n        let apiSecret = cloudinary!.config.apiSecret\n        \n        XCTAssertNotNil(cloudName, \"cloudName Should not be nil\")\n        XCTAssertNotNil(apiSecret, \"apiSecret Should not be nil\")\n        \n        let configWithEmptyApiKey = CLDConfiguration(cloudName: cloudName, apiKey: apiKey, apiSecret: apiSecret, secure: true)\n        let cloudinaryWithNoKey = CLDCloudinary(configuration: configWithEmptyApiKey, sessionConfiguration: .default)\n        \n        XCTAssertEqual(cloudinaryWithNoKey.config.apiKey, \"\", \"Should be empty\")\n        \n        // When\n        let params = CLDUploadRequestParams()\n        params.setApiKey(cloudinary!.config.apiKey!)\n        \n        cloudinaryWithNoKey.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Expect\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n    \n    func test_upload_ApiKeyWithConfig() {\n        \n        // Given\n        \n        XCTAssertNotNil(cloudinary!.config.apiKey, \"Must set api key for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed with the key in config\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        // When\n\n        cloudinary!.createUploader().signedUpload(url: file, params: CLDUploadRequestParams()).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        // Expect\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n    \n\n    \n    // MARK: - eval\n    func test_eval_JavaScriptAddTag_shouldAddTag() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        \n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        let tagInput = \"blurry\"\n        let input = \"upload_options.tags = '\\(tagInput)'\"\n        \n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let params = CLDUploadRequestParams()\n        params.setEval(input)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        \n        if let tags = result?.tags {\n            XCTAssertTrue(tags.contains(tagInput), \"eval field in this scenario should add tag via javascript code, then in the upload result the tag should appear\")\n        }\n        else {\n            XCTFail(\"eval field in this scenario should add tag via javascript code, then in the upload result the tag should appear\")\n        }\n    }\n    func test_eval_JavaScriptAddTagWithCondition_shouldAddTag() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        \n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        let tagInput = \"blurry\"\n        let input = \"if (resource_info.quality_analysis.focus > 0.5) { upload_options.tags = '\\(tagInput)' }\"\n        \n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let params = CLDUploadRequestParams()\n        params.setEval(input)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            \n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        \n        if let tags = result?.tags {\n            XCTAssertTrue(tags.contains(tagInput), \"eval field in this scenario should add tag via javascript code, then in the upload result the tag should appear\")\n        }\n        else {\n            XCTFail(\"eval field in this scenario should add tag via javascript code, then in the upload result the tag should appear\")\n        }\n    }\n\n    func testManualModeration() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setModeration(.manual)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n\n        if let moderationArr = result?.moderation as? NSArray {\n            if let mod = moderationArr.firstObject as? NSDictionary,\n               let status = mod[\"status\"] as? String,\n               let kind = mod[\"kind\"] as? String {\n                XCTAssertEqual(status, \"pending\")\n                XCTAssertEqual(kind, \"manual\")\n            } else {\n                XCTFail(\"Moderation dictionary should hold its status and kind.\")\n            }\n        } else {\n            XCTFail(\"Manual moderation response should be a dictionary holding a moderation dictionary.\")\n        }\n\n    }\n    \n    func testBackgroundRemoval() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setBackgroundRemoval(\"illegal\")\n        params.setResourceType(.image)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNil(result, \"result should be nil\")\n        XCTAssertNotNil(error, \"error should not be nil\")\n\n        if let userInfo = error?.userInfo, let errMessage = userInfo[\"message\"] as? String {\n            XCTAssertNotNil(errMessage.range(of: \"Background removal is invalid\"))\n            XCTAssertEqual(userInfo[\"statusCode\"] as? Int, 400)\n        } else {\n            XCTFail(\"Error should hold a message in its user info.\")\n        }\n    }\n    \n    func testFilenameOverride() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed and uploaded filename should change to 'overridden'\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setFilenameOverride(\"overridden\")\n        params.setUseFilename(true)\n        params.setResourceType(.image)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n        \n        if let originalFilename = result?.originalFilename {\n            XCTAssertEqual(originalFilename, \"overridden\", \"Filename mismatch, replaced name should be 'overridden'\")\n        } else {\n            XCTFail(\"Upload param 'original_filename' is missing\")\n        }\n    }\n\n    func testRawConversion() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .docx\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setRawConvert(\"illegal\")\n        params.setResourceType(.raw)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNil(result, \"result should be nil\")\n        XCTAssertNotNil(error, \"error should not be nil\")\n\n        if let userInfo = error?.userInfo, let errMessage = userInfo[\"message\"] as? String {\n            XCTAssertNotNil(errMessage.range(of: \"Raw convert is invalid\"))\n            XCTAssertEqual(userInfo[\"statusCode\"] as? Int, 400)\n        } else {\n            XCTFail(\"Error should hold a message in its user info.\")\n        }\n    }\n\n    func testCategorization() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setCategorization(\"illegal\")\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNil(result, \"result should be nil\")\n        XCTAssertNotNil(error, \"error should not be nil\")\n\n        if let userInfo = error?.userInfo, let errMessage = userInfo[\"message\"] as? String {\n            XCTAssertNotNil(errMessage.range(of: \"Categorization item illegal is not valid\"))\n            XCTAssertEqual(userInfo[\"statusCode\"] as? Int, 400)\n        } else {\n            XCTFail(\"Error should hold a message in its user info.\")\n        }\n    }\n    \n    func testDetection() {\n\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setDetection(\"illegal\")\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNil(result, \"result should be nil\")\n        XCTAssertNotNil(error, \"error should not be nil\")\n\n        if let errMessage = error?.userInfo[\"message\"] as? String {\n            XCTAssertNotNil(errMessage.range(of: \"Detection invalid\"))\n        } else {\n            XCTFail(\"Error should hold a message in its user info.\")\n        }\n    }\n    \n    func testCldIsRemoteUrl(){\n        let remoteUrls = [\n            \"ftp://ftp.cloudinary.com/images/old_logo.png\",\n            \"http://cloudinary.com/images/old_logo.png\",\n            \"https://cloudinary.com/images/old_logo.png\",\n            \"s3://s3-us-west-2.amazonaws.com/cloudinary/images/old_logo.png\",\n            \"gs://cloudinary/images/old_logo.png\",\n            \"data:image/gif;charset=utf-8;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\",\n            \"data:image/gif;param1=value1;param2=value2;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\",\n            \"data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPg\",\n            \"data:image/gif;charset=utf8;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"\n        ]\n        \n        remoteUrls.forEach({XCTAssertTrue($0.cldIsRemoteUrl())})\n        \n        let notRemoteUrls = [\n            \"not a remote url\",\n            \"http/almost\",\n            \"\"\n        ]\n        \n        notRemoteUrls.forEach({XCTAssertFalse($0.cldIsRemoteUrl())})\n    }\n    \n    func testQualityOverride(){\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n        let result = uploadResource()\n        \n        validateQualityOverride(publicId: result.publicId!, quality: \"80\", shouldSucceed: true)\n        validateQualityOverride(publicId: result.publicId!, quality: \"80:420\", shouldSucceed: true)\n        validateQualityOverride(publicId: result.publicId!, quality: \"80:421\", shouldSucceed: false)\n        validateQualityOverride(publicId: result.publicId!, quality: \"auto:best\", shouldSucceed: true)\n        validateQualityOverride(publicId: result.publicId!, quality: \"auto:advanced\", shouldSucceed: false)\n        validateQualityOverride(publicId: result.publicId!, quality: \"none\", shouldSucceed: true)\n    }\n\n    //MARK: - Helpers\n\n    func uploadResource() -> CLDUploadResult {\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        let resource: TestResourceType = .borderCollie\n        let file = resource.url\n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        \n        cloudinary!.createUploader().signedUpload(url: file, params: CLDUploadRequestParams())\n            .response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            if let error = error {\n                print(error)\n            }\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        XCTAssertNotNil(result, \"result should not be nil\")\n        \n        return result!\n    }\n\n    func testUploadLarge() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload large should succeed\")\n        let file = TestResourceType.dog.url\n        let filename = TestResourceType.dog.fileName\n        var requestResult: CLDUploadResult?\n        var requestError: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setResourceType(CLDUrlResourceType.video)\n        params.setUseFilename(true)\n\n\n        cloudinary!.createUploader().signedUploadLarge(url: file, params: params, chunkSize: 5 * 1024 * 1024).response({ (result, error) in\n            requestResult = result\n            requestError = error\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(requestResult, \"result should not be nil\")\n        XCTAssertNil(requestError, \"error should be nil\")\n        XCTAssertTrue(isUsedFilename(filename: filename, publicId: requestResult?.publicId))\n    }\n\n    func testAutoChaptering() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed and return playback url\")\n        let file = TestResourceType.dog.url\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setColors(true)\n        params.setResourceType(.video)\n        params.setAutoChpatering(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNotNil(result?.playbackUrl, \"playback url should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n    func testAutoTranscription() {\n        XCTAssertNotNil(cloudinary!.config.apiSecret, \"Must set api secret for this test\")\n\n        let expectation = self.expectation(description: \"Upload should succeed and return playback url\")\n        let file = TestResourceType.dog.url\n\n        var result: CLDUploadResult?\n        var error: NSError?\n\n        let params = CLDUploadRequestParams()\n        params.setColors(true)\n        params.setResourceType(.video)\n        params.setAutoTranscription(true)\n        cloudinary!.createUploader().signedUpload(url: file, params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n\n            expectation.fulfill()\n        })\n\n        waitForExpectations(timeout: timeout, handler: nil)\n\n        XCTAssertNotNil(result, \"result should not be nil\")\n        XCTAssertNotNil(result?.playbackUrl, \"playback url should not be nil\")\n        XCTAssertNil(error, \"error should be nil\")\n    }\n\n\n    func validateQualityOverride(publicId: String, quality: String, shouldSucceed: Bool){\n\n        let qualityOverrideExpectation = self.expectation(description: \"Explicit call with quality override should succeed\")\n        var result: CLDUploadResult?\n        var error: NSError?\n        \n        let params = CLDExplicitRequestParams().setQualityOverride(quality)\n        cloudinary!.createManagementApi().explicit(publicId, type: \"upload\", params: params).response({ (resultRes, errorRes) in\n            result = resultRes\n            error = errorRes\n            if let error = error {\n                print(error)\n            }\n            qualityOverrideExpectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        let notNil = shouldSucceed ? result : error\n        XCTAssertNotNil(notNil, \"quality \\(quality) should \\(shouldSucceed ? \"succeed\" : \"fail\")\")\n    }\n    \n    func createUploadPresetIfNeeded(_ uploadPresetUrl: String, presetName: String) {\n        let semaphore = DispatchSemaphore(value: 0)\n        if let url = URL(string: \"\\(uploadPresetUrl)/\\(presetName)\") {\n            let session = URLSession.shared\n            session.dataTask(with: url, completionHandler: { (returnData, response, error) -> () in\n                if let returnData = returnData {\n                    if let strData = String(data: returnData, encoding: String.Encoding.utf8) {\n                        if strData.range(of: \"Can't find upload preset named\") != nil {\n                            if let url = URL(string: uploadPresetUrl) {\n                                var request = URLRequest(url: url)\n                                request.httpMethod = \"POST\"\n                                request.addValue(\"application/x-www-form-urlencoded\", forHTTPHeaderField: \"Content-Type\")\n                                let params = \"name=\\(presetName)&unsigned=true&tags=ios_sdk_test\"\n                                let httpData = params.data(using: String.Encoding.utf8)\n                                request.httpBody = httpData\n                                session.dataTask(with: request, completionHandler: { (returnData, response, error) -> () in\n                                    if let returnData = returnData,\n                                       let strData = String(data: returnData, encoding: String.Encoding.utf8) {\n                                        print(strData)\n                                    }\n                                    semaphore.signal()\n                                }).resume()\n                            } else {\n                                XCTFail(\"preset request failed\")\n                                semaphore.signal()\n                            }\n                        } else {\n                            semaphore.signal()\n                        }\n                    } else {\n                        XCTFail(\"preset request failed\")\n                        semaphore.signal()\n                    }\n                } else {\n                    XCTFail(\"preset request failed\")\n                    semaphore.signal()\n                }\n            }).resume()\n        } else {\n            XCTFail(\"preset request failed\")\n            semaphore.signal()\n        }\n\n        _ = semaphore.wait(timeout: DispatchTime.distantFuture)\n    }\n}\n\n"
  },
  {
    "path": "Example/Tests/ParamTests/UploadRequestParamsTests.swift",
    "content": "//\n//  UploadRequestParamsTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass UploadRequestParamsTests: BaseTestCase {\n    \n    var sut : CLDUploadRequestParams!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = CLDUploadRequestParams()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - accessibility analysis\n    func test_getAccessibilityAnalysis_unset_shouldNotStoreValue() {\n        \n        // Then\n        XCTAssertNil(sut.accessibilityAnalysis, \"unset property should not be stored in params\")\n    }\n    func test_setAccessibilityAnalysis_true_shouldStoreTrueValue() {\n        \n        // When\n        sut.setAccessibilityAnalysis(true)\n        \n        // Then\n        XCTAssertTrue(sut.accessibilityAnalysis == true, \"setting property to true should store true in params\")\n    }\n    func test_setAccessibilityAnalysis_trueThenFalse_shouldUpdateValue() {\n        \n        // When\n        sut.setAccessibilityAnalysis(true)\n        sut.setAccessibilityAnalysis(false)\n        \n        // Then\n        XCTAssertTrue(sut.accessibilityAnalysis == false, \"updating property to false value should store false in params\")\n    }\n    \n    // MARK: - ocr\n    func test_getOcr_unset_shouldNotStoreValue() {\n        \n        // Then\n        XCTAssertFalse(sut.ocr, \"unset property should not be false\")\n        XCTAssertFalse(sut.params.keys.contains(\"ocr\"), \"unset property should not be stored in params\")\n    }\n    \n    func test_setOcr_true_shouldStoreTrueValue() {\n        \n        // When\n        sut.setOcr(true)\n        \n        // Then\n        XCTAssertTrue(sut.ocr == true, \"setting property to true should store true in params\")\n        XCTAssertTrue(sut.params.keys.contains(\"ocr\"), \"setting property to true should store true in params\")\n    }\n    \n    func test_setOcr_trueThenFalse_shouldRemoveValue() {\n        \n        // When\n        sut.setOcr(true)\n        sut.setOcr(false)\n        \n        // Then\n        XCTAssertFalse(sut.ocr, \"updating ocr property to false value should remove store property from params\")\n        XCTAssertFalse(sut.params.keys.contains(\"ocr\"), \"updating ocr property to false value should remove store property from params\")\n    }\n    \n    // MARK: - eval\n    func test_getEval_unset_shouldNotStoreValue() {\n        \n        XCTAssertNil(sut.eval, \"unset property should not be stored in params\")\n    }\n    func test_setEval_String_shouldStoreValue() {\n        \n        // Given\n        let input = \"evalString\"\n        \n        // When\n        sut.setEval(input)\n        \n        // Then\n        XCTAssertEqual(sut.eval, input, \"set property should be stored in params\")\n    }\n    func test_backgroundRemoval_String_shouldStoreValue() {\n        \n        // Given\n        let input = \"backgroundString\"\n        \n        // When\n        sut.setBackgroundRemoval(input)\n        \n        // Then\n        XCTAssertEqual(sut.backgroundRemoval, input, \"set property should be stored in params\")\n    }\n    func test_setOcr_updateValue_shouldUpdateValue() {\n\n        // Given\n        let initialInput = \"evalString\"\n        let updatedInput = \"updatedString\"\n        \n        // When\n        sut.setEval(initialInput)\n        sut.setEval(updatedInput)\n\n        // Then\n        XCTAssertEqual(sut.eval, updatedInput, \"Init without longUrlSignature should store the default false value\")\n    }\n    \n    // MARK: - quality analysis\n    func test_getQualityAnalysis_unset_shouldNotStoreValue() {\n        \n        XCTAssertNil(sut.qualityAnalysis, \"unset property should not be stored in params\")\n    }\n    func test_setQualityAnalysis_String_shouldStoreValue() {\n        \n        // Given\n        let input = true\n        \n        // When\n        sut.setQualityAnalysis(input)\n        \n        // Then\n        XCTAssertEqual(sut.qualityAnalysis, input, \"set property should be stored in params\")\n    }\n    func test_setQualityAnalysis_updateValue_shouldUpdateValue() {\n\n        // Given\n        let initialInput = true\n        let updatedInput = false\n        \n        // When\n        sut.setQualityAnalysis(initialInput)\n        sut.setQualityAnalysis(updatedInput)\n\n        // Then\n        XCTAssertEqual(sut.qualityAnalysis, updatedInput, \"updated property should be stored in params\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/Preprocess/PreprocessTests.swift",
    "content": "//\n//  PreprocessTests.swift\n//  CloudinaryTests\n//\n//  Created by Nitzan Jaitman on 04/01/2018.\n//  Copyright © 2018 Cloudinary. All rights reserved.\n//\n\nimport XCTest\nimport UIKit\n@testable import Cloudinary\n\nclass PreprocessTests: BaseTestCase {\n    \n    var sut: UIImage!\n    \n    // MARK: - setup and tearDown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        super.tearDown()\n        sut = nil\n    }\n    \n    // MARK: - get image\n    fileprivate func getImage()->UIImage {\n        let bundle = Bundle(for: PreprocessTests.self)\n        let url = bundle.url(forResource: \"borderCollie\", withExtension: \"jpg\")!\n        \n        return CLDPreprocessHelpers.resizeImage(image: UIImage(contentsOfFile: url.path)!, requiredSize: CGSize(width: 300, height:300))\n    }\n    \n    fileprivate func getFullSizeImage(_ resourceType: NetworkBaseTest.TestResourceType = .borderCollie) -> UIImage {\n        let bundle = Bundle(for: PreprocessTests.self)\n        let url = bundle.url(forResource: resourceType.fileName, withExtension: resourceType.resourceExtension)!\n        \n        return UIImage(contentsOfFile: url.path)!\n    }\n    \n    // MARK: - limit\n    func testLimit() {\n        let image = getImage()\n        \n        var modified = try! CLDPreprocessHelpers.limit(width: 5000, height: 5000)(image)\n        XCTAssertEqual(image.size, modified.size)\n        \n        modified = try! CLDPreprocessHelpers.limit(width: 5000, height: 10)(image)\n        XCTAssertEqual(modified.size, CGSize(width: 10, height:10))\n        \n        modified = try! CLDPreprocessHelpers.limit(width: 10, height: 5000)(image)\n        XCTAssertEqual(modified.size, CGSize(width: 10, height:10))\n        \n        modified = try! CLDPreprocessHelpers.limit(width: 200, height: 300)(image)\n        XCTAssertEqual(modified.size, CGSize(width: 200, height:200))\n        \n        modified = try! CLDPreprocessHelpers.limit(width: 300, height: 200)(image)\n        XCTAssertEqual(modified.size, CGSize(width: 200, height:200))\n        \n        modified = try! CLDPreprocessHelpers.limit(width: 400, height: 200)(image)\n        XCTAssertEqual(modified.size, CGSize(width: 200, height:200))\n        \n        modified = try! CLDPreprocessHelpers.limit(width: 200, height: 400)(image)\n        XCTAssertEqual(modified.size, CGSize(width: 200, height:200))\n        \n        modified = try! CLDPreprocessHelpers.limit(width: 500, height: 300)(image)\n        XCTAssertEqual(modified.size, CGSize(width: 300, height:300))\n        \n        modified = try! CLDPreprocessHelpers.limit(width: 300, height: 500)(image)\n        XCTAssertEqual(modified.size, CGSize(width: 300, height:300))\n    }\n    \n    // MARK: - crop\n    func test_crop_small_shouldCropToSize() {\n        \n        // Given\n        let image = getFullSizeImage()\n        let imageNewRect = CGRect(x: 0, y: 0, width: 5, height: 5)\n        \n        // When\n        sut = try! CLDPreprocessHelpers.crop(cropRect: imageNewRect)(image)\n        \n        // Then\n        XCTAssertEqual(sut.size ,imageNewRect.size, \"image should be cropped to the requested size\")\n    }\n    func test_crop_big_shouldCropToSize()   {\n        \n        // Given\n        let image = getFullSizeImage()\n        let imageNewRect = CGRect(x: 0, y: 0, width: 900, height: 900)\n        \n        // When\n        sut = try! CLDPreprocessHelpers.crop(cropRect: imageNewRect)(image)\n        \n        // Then\n        XCTAssertEqual(sut.size, imageNewRect.size, \"image should be cropped to the requested size\")\n    }\n    func test_crop_widthOutOfBounds_shouldCropToSize()  {\n        \n        // Given\n        let image = getFullSizeImage()\n        let imageNewRect = CGRect(x: 0, y: 0, width: 1900, height: 40) // borderCollie image size 960 * 960\n        \n        // Then\n        XCTAssertThrowsError(try CLDPreprocessHelpers.crop(cropRect: imageNewRect)(image), \"trying to crop an image out of bounds should throw an error\")\n    }\n    func test_crop_heightOutOfBounds_shouldCropToSize() {\n        \n        // Given\n        let image = getFullSizeImage()\n        let imageNewRect = CGRect(x: 0, y: 0, width: 40, height: 1900) // borderCollie image size 960 * 960\n        \n        // Then\n        XCTAssertThrowsError(try CLDPreprocessHelpers.crop(cropRect: imageNewRect)(image), \"trying to crop an image out of bounds should throw an error\")\n    }\n    func test_crop_XOutOfBounds_shouldCropToSize() {\n        \n        // Given\n        let image = getFullSizeImage()\n        let imageNewRect = CGRect(x: 950, y: 0, width: 40, height: 40) // borderCollie image size 960 * 960\n        \n        // Then\n        XCTAssertThrowsError(try CLDPreprocessHelpers.crop(cropRect: imageNewRect)(image), \"trying to crop an image out of bounds should throw an error\")\n    }\n    func test_crop_YOutOfBounds_shouldCropToSize() {\n        \n        // Given\n        let image = getFullSizeImage()\n        let imageNewRect = CGRect(x: 0, y: 950, width: 40, height: 40) // borderCollie image size 960 * 960\n        \n        // Then\n        XCTAssertThrowsError(try CLDPreprocessHelpers.crop(cropRect: imageNewRect)(image), \"trying to crop an image out of bounds should throw an error\")\n    }\n    \n    // MARK: - rotate\n    func test_rotate_45_shouldRotateToAngle() {\n        \n        // Given\n        let image = getFullSizeImage()\n        let imageExpectedSize = CGSize(width: 1357, height: 1357)\n        \n        // When\n        sut = try! CLDPreprocessHelpers.rotate(degrees: 45)(image)\n        \n        // Then\n        XCTAssertEqual(sut.size ,imageExpectedSize, \"image should be rotated to the requested angle (this should change the image size)\")\n    }\n    func test_rotate_90_shouldRotateToAngle() {\n        \n        // Given\n        let image = getFullSizeImage(.logo)\n        let imageExpectedSize = CGSize(width: image.size.height, height: image.size.width)\n        \n        // When\n        sut = try! CLDPreprocessHelpers.rotate(degrees: 90)(image)\n        \n        // Then\n        XCTAssertEqual(sut.size ,imageExpectedSize, \"image should be rotated to the requested angle (this should change the image size)\")\n    }\n    func test_rotate_180_shouldRotateToAngle() {\n        \n        // Given\n        let image = getFullSizeImage()\n        let imageExpectedSize = image.size\n        \n        // When\n        sut = try! CLDPreprocessHelpers.rotate(degrees: 180)(image)\n        \n        // Then\n        XCTAssertEqual(sut.size ,imageExpectedSize, \"image should be rotated to the requested angle (this should change the image size)\")\n    }\n    func test_rotate_810_shouldRotateToAngle() {\n        \n        // Given\n        let image = getFullSizeImage()\n        let imageExpectedSize = CGSize(width: image.size.height, height: image.size.width)\n        \n        // When\n        sut = try! CLDPreprocessHelpers.rotate(degrees: 810)(image)\n        \n        // Then\n        XCTAssertEqual(sut.size ,imageExpectedSize, \"image should be rotated to the requested angle (this should change the image size)\")\n    }\n    func test_rotate_45png_shouldRotateToAngle()   {\n        \n        // Given\n        let image = getFullSizeImage(.logo)\n        let imageExpectedSize = CGSize(width: 206, height: 206)\n        \n        // When\n        sut = try! CLDPreprocessHelpers.rotate(degrees: 45)(image)\n        \n        // Then\n        XCTAssertEqual(sut.size ,imageExpectedSize, \"image should be rotated to the requested angle (this should change the image size)\")\n    }\n    func test_rotate_CIImage_shouldRotateToAngle() {\n        \n        // Given\n        let ciimage = CIImage(image: getFullSizeImage(.logo))!\n        let uiimageFromCIImage = UIImage(ciImage: ciimage)\n        \n        let imageExpectedSize = CGSize(width: 206, height: 206)\n        \n        // When\n        sut = try! CLDPreprocessHelpers.rotate(degrees: 45)(uiimageFromCIImage)\n        \n        // Then\n        XCTAssertNil(uiimageFromCIImage.cgImage, \"image.cgImage should be nil\")\n        XCTAssertEqual(sut.size ,imageExpectedSize, \"image should be rotated to the requested angle (this should change the image size)\")\n    }\n    func test_rotate_shouldEqualPrePreparedImage() {\n        \n        // Given\n        let image = getFullSizeImage()\n        let prePreparedImage = getFullSizeImage(.borderCollieRotatedPng)\n        \n        // When\n        sut = try! CLDPreprocessHelpers.rotate(degrees: 45)(image)\n        \n        // Then\n        XCTAssertEqual(sut.size, prePreparedImage.size, \"rotated image should be equal to pre prepared image\")\n    }\n    \n    // MARK: - dimension validator\n    func testDimensionValidator() {\n        let image = getImage()\n        \n        var modified = try? CLDPreprocessHelpers.dimensionsValidator(minWidth: 300, maxWidth: 300, minHeight: 300, maxHeight: 300)(image)\n        XCTAssertNotNil(modified)\n        \n        modified = try? CLDPreprocessHelpers.dimensionsValidator(minWidth: 300, maxWidth: 3000, minHeight: 300, maxHeight: 3000)(image)\n        XCTAssertNotNil(modified)\n        \n        modified = try? CLDPreprocessHelpers.dimensionsValidator(minWidth: 10, maxWidth: 3000, minHeight: 10, maxHeight: 3000)(image)\n        XCTAssertNotNil(modified)\n        \n        modified = try? CLDPreprocessHelpers.dimensionsValidator(minWidth: 10, maxWidth: 300, minHeight: 10, maxHeight: 300)(image)\n        XCTAssertNotNil(modified)\n        \n        modified = try? CLDPreprocessHelpers.dimensionsValidator(minWidth: 400, maxWidth: 3000, minHeight: 30, maxHeight: 3000)(image)\n        XCTAssertNil(modified)\n        \n        modified = try? CLDPreprocessHelpers.dimensionsValidator(minWidth: 300, maxWidth: 300, minHeight: 400, maxHeight: 3000)(image)\n        XCTAssertNil(modified)\n        \n        modified = try? CLDPreprocessHelpers.dimensionsValidator(minWidth: 300, maxWidth: 300, minHeight: 100, maxHeight: 200)(image)\n        XCTAssertNil(modified)\n        \n        modified = try? CLDPreprocessHelpers.dimensionsValidator(minWidth: 100, maxWidth: 200, minHeight: 300, maxHeight: 300)(image)\n        XCTAssertNil(modified)\n    }\n}\n"
  },
  {
    "path": "Example/Tests/Preprocess/VideoPreprocessTests.swift",
    "content": "import XCTest\nimport AVFoundation\n@testable import Cloudinary\n\nclass VideoPreprocessTests: XCTestCase {\n\n    var videoURL: URL!\n    var invalidVideoURL: URL!\n    var notAVideoURL: URL!\n\n    // MARK: - Setup and TearDown\n    override func setUp() {\n        super.setUp()\n        let bundle = Bundle(for: VideoPreprocessTests.self)\n        videoURL = bundle.url(forResource: \"dog\", withExtension: \"mp4\")\n        invalidVideoURL = URL(fileURLWithPath: \"/invalid/path/to/video.mp4\")\n        notAVideoURL = bundle.url(forResource: \"empty_string\", withExtension: \"txt\")\n    }\n\n    override func tearDown() {\n        super.tearDown()\n        videoURL = nil\n        invalidVideoURL = nil\n        notAVideoURL = nil\n    }\n\n    // MARK: - Helper Methods\n    fileprivate func getVideoTranscode(from url: URL) -> CLDVideoTranscode {\n        return CLDVideoTranscode(sourceURL: url)\n    }\n\n    // MARK: - Tests\n    func testSetOutputFormat() {\n        var video = getVideoTranscode(from: videoURL)\n\n        video = try! CLDVideoPreprocessHelpers.setOutputFormat(format: .mp4)(video)\n        XCTAssertEqual(video.outputFormat, .mp4)\n\n        video = try! CLDVideoPreprocessHelpers.setOutputFormat(format: .mov)(video)\n        XCTAssertEqual(video.outputFormat, .mov)\n    }\n\n    func testSetOutputDimensions() {\n        var video = getVideoTranscode(from: videoURL)\n        let dimensions = CGSize(width: 1280, height: 720)\n\n        video = try! CLDVideoPreprocessHelpers.setOutputDimensions(dimensions: dimensions)(video)\n        XCTAssertEqual(video.outputDimensions, dimensions)\n    }\n\n    func testSetCompressionPreset() {\n        var video = getVideoTranscode(from: videoURL)\n        let preset = AVAssetExportPresetHighestQuality\n\n        video = try! CLDVideoPreprocessHelpers.setCompressionPreset(preset: preset)(video)\n        XCTAssertEqual(video.compressionPreset, preset)\n    }\n\n    func testDimensionsValidator() {\n        var video = getVideoTranscode(from: videoURL)\n        let dimensions = CGSize(width: 1280, height: 720)\n\n        video = try! CLDVideoPreprocessHelpers.setOutputDimensions(dimensions: dimensions)(video)\n\n        var modifiedVideo = try? CLDVideoPreprocessHelpers.dimensionsValidator(minWidth: 100, maxWidth: 2000, minHeight: 100, maxHeight: 2000)(video)\n        XCTAssertNotNil(modifiedVideo)\n\n        modifiedVideo = try? CLDVideoPreprocessHelpers.dimensionsValidator(minWidth: 1300, maxWidth: 2000, minHeight: 100, maxHeight: 2000)(video)\n        XCTAssertNil(modifiedVideo)\n    }\n\n    func testInvalidURL() {\n        let video = getVideoTranscode(from: invalidVideoURL)\n        XCTAssertThrowsError(try CLDVideoPreprocessHelpers.setOutputFormat(format: .mp4)(video)) { error in\n            XCTAssertEqual((error as NSError).domain, \"CLDVideoPreprocessHelpers\")\n        }\n    }\n\n    func testNotAVideo() {\n        let video = getVideoTranscode(from: notAVideoURL)\n        XCTAssertThrowsError(try CLDVideoPreprocessHelpers.setOutputFormat(format: .mp4)(video)) { error in\n            XCTAssertEqual((error as NSError).domain, \"CLDVideoPreprocessHelpers\")\n        }\n    }\n\n    func testMissingVideoTrack() {\n        let video = getVideoTranscode(from: videoURL)\n        XCTAssertTrue(video.hasVideoTrack, \"Original video should have a video track\")\n\n        let noVideoTrackURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString).appendingPathExtension(\"mov\")\n\n        let fileManager = FileManager.default\n        let fileContents = Data()\n        fileManager.createFile(atPath: noVideoTrackURL.path, contents: fileContents)\n\n        let noVideoTrackTranscode = getVideoTranscode(from: noVideoTrackURL)\n        XCTAssertFalse(noVideoTrackTranscode.hasVideoTrack, \"The mock video should not have a video track\")\n\n        do {\n            _ = try CLDVideoPreprocessHelpers.setOutputFormat(format: .mp4)(noVideoTrackTranscode)\n            XCTFail(\"Expected to throw an error for missing video track\")\n        } catch {\n            XCTAssertEqual((error as NSError).domain, \"CLDVideoPreprocessHelpers\")\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "Example/Tests/StringUtilsTest.swift",
    "content": "//\n// Created by Nitzan Jaitman on 02/09/2018.\n// Copyright (c) 2018 Cloudinary. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import Cloudinary\n\nclass StringUtilsTests: BaseTestCase {\n    override func setUp() {\n        super.setUp()\n    }\n\n    override func tearDown() {\n        super.tearDown()\n    }\n\n    func testBase64Encode (){\n        let str = \"ad?.,x09~!@!\"\n        XCTAssertEqual(\"YWQ/Lix4MDl+IUAh\", str.cldBase64Encode())\n    }\n    \n    func testBase64UrlEncode(){\n        let str = \"ad?.,x09~!@!\"\n        XCTAssertEqual(\"YWQ_Lix4MDl-IUAh\", str.cldBase64UrlEncode())\n    }\n}\n"
  },
  {
    "path": "Example/Tests/TestableCloudinary.swift",
    "content": "//\n//  TestableCloudinary.swift\n//  Cloudinary_Tests\n//\n//  Created by Adi Mizrahi on 30/01/2025.\n//  Copyright © 2025 CocoaPods. All rights reserved.\n//\n\nimport Cloudinary\n\nclass TestableCloudinary {\n    static func getNetworkCoordinator(from cloudinary: CLDCloudinary) -> AnyObject? {\n        let mirror = Mirror(reflecting: cloudinary)\n        for child in mirror.children {\n            if String(describing: type(of: child.value)).contains(\"CLDNetworkCoordinator\") {\n                return child.value as AnyObject\n            }\n        }\n        return nil\n    }\n}\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDConditionExpressionTests/CLDConditionExpressionHelpersTests.swift",
    "content": "//\n//  CLDConditionExpressionHelpersTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass CLDConditionExpressionHelpersTests: BaseTestCase {\n    \n    var sut : CLDConditionExpression!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n\n    // MARK: - widthWithOperator\n    func test_widthWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"w_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().width(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_widthWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"w_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().width(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_widthWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"w_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().width(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_widthWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"w_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().width(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_widthWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"w_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().width(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - heightWithOperator\n    func test_heightWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"h_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().height(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_heightWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"h_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().height(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_heightWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"h_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().height(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_heightWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"h_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().height(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_heightWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"h_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().height(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - aspectRatioWithOperator\n    func test_aspectRatioWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"ar_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().aspectRatio(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_aspectRatioWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"ar_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().aspectRatio(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_aspectRatioWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"ar_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().aspectRatio(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_aspectRatioWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"ar_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().aspectRatio(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_aspectRatioWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"ar_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().aspectRatio(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - initialWidthWithOperator\n    func test_initialWidthWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"iw_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().initialWidth(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialWidthWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"iw_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().initialWidth(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialWidthWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"iw_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().initialWidth(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialWidthWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"iw_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().initialWidth(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialWidthWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"iw_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().initialWidth(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - initialHeightWithOperator\n    func test_initialHeightWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"ih_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().initialHeight(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialHeightWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"ih_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().initialHeight(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialHeightWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"ih_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().initialHeight(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialHeightWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"ih_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().initialHeight(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialHeightWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"ih_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().initialHeight(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - initialAspectRatioWithOperator\n    func test_initialAspectRatioWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"iar_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().initialAspectRatio(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialAspectRatioWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"iar_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().initialAspectRatio(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialAspectRatioWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"iar_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().initialAspectRatio(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialAspectRatioWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"iar_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().initialAspectRatio(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialAspectRatioWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"iar_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().initialAspectRatio(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - pageCountWithOperator\n    func test_pageCountWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"pc_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().pageCount(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageCountWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"pc_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().pageCount(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageCountWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"pc_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().pageCount(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageCountWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"pc_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().pageCount(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageCountWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"pc_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().pageCount(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - faceCountWithOperator\n    func test_faceCountWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"fc_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().faceCount(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_faceCountWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"fc_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().faceCount(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_faceCountWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"fc_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().faceCount(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_faceCountWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"fc_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().faceCount(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_faceCountWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"fc_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().faceCount(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - tagsWithOperator\n    func test_tagsWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"tags_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().tags(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_tagsWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"tags_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().tags(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_tagsWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"tags_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().tags(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_tagsWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"tags_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().tags(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_tagsWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"tags_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().tags(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - pageXOffsetWithOperator\n    func test_pageXOffsetWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"px_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().pageXOffset(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageXOffsetWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"px_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().pageXOffset(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageXOffsetWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"px_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().pageXOffset(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageXOffsetWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"px_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().pageXOffset(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageXOffsetWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"px_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().pageXOffset(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - pageYOffsetWithOperator\n    func test_pageYOffsetWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"py_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().pageYOffset(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageYOffsetWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"py_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().pageYOffset(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageYOffsetWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"py_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().pageYOffset(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageYOffsetWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"py_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().pageYOffset(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_pageYOffsetWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"py_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().pageYOffset(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - illustrationScoreWithOperator\n    func test_illustrationScoreWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"ils_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().illustrationScore(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_illustrationScoreWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"ils_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().illustrationScore(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_illustrationScoreWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"ils_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().illustrationScore(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_illustrationScoreWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"ils_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().illustrationScore(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_illustrationScoreWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"ils_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().illustrationScore(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - currentPageIndexWithOperator\n    func test_currentPageIndexWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"cp_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().currentPageIndex(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_currentPageIndexWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"cp_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().currentPageIndex(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_currentPageIndexWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"cp_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().currentPageIndex(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_currentPageIndexWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"cp_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().currentPageIndex(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_currentPageIndexWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"cp_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().currentPageIndex(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - durationWithOperator\n    func test_durationWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"du_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().duration(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_durationWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"du_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().duration(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_durationWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"du_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().duration(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_durationWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"du_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().duration(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_durationWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"du_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().duration(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - initialDurationWithOperator\n    func test_initialDurationWithOperator_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"<\"\n        let value: Int = 100\n        \n        let expectedValueResult = \"idu_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression().initialDuration(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialDurationWithOperator_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \">\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"idu_gt_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().initialDuration(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialDurationWithOperator_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"idu_eq_30.3\"\n        \n        // When\n        sut = CLDConditionExpression().initialDuration(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialDurationWithOperator_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDExpression.initialHeight().add(by: 20)\n        \n        let expectedValueResult = \"idu_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().initialDuration(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    func test_initialDurationWithOperator_conditionValue_shouldAppendValidValue() {\n        \n        // Given\n        let stringOperator = \"=\"\n        let value = CLDConditionExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"idu_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().initialDuration(stringOperator, value)\n        \n        // Then\n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDConditionExpressionTests/CLDConditionExpressionTests.m",
    "content": "//\n//  ObjcCLDConditionExpressionTests.m\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"ObjcBaseTestCase.h\"\n\n@interface ObjcCLDConditionExpressionTests : ObjcBaseTestCase\n\n@end\n\n@implementation ObjcCLDConditionExpressionTests\n\nCLDConditionExpression *conSut;\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n}\n\n- (void)tearDown {\n    [super tearDown];\n    conSut = nil;\n}\n\n// MARK: - complexConditionExpression\n- (void)test_complexConditionExpression_shouldCreateValidExpression {\n        \n    // Given\n    NSString* expectedResult = @\"w_add_30_and_h_gt_30_or_ar_eq_20\";\n    \n    // When\n    conSut = [[[[[[CLDConditionExpression width] addByInt:30] and] height:@\">\" intValue:30] or] aspectRatio:@\"eq\" string:@\"20\"];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n\n// MARK: - creatingConditionExpression\n- (void)test_creatingConditionExpression_widthAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"w_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression width];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_heightSubtract_shouldCreateValidExpression {\n        \n    // Given\n    float input = 30.3;\n    \n    NSString* expectedResult = @\"h_sub_30.3\";\n    \n    // When\n    conSut = [CLDConditionExpression height];\n    [conSut subtractByFloat: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_initialWidthMultiple_shouldCreateValidExpression {\n        \n    // Given\n    NSString* input = @\"30\";\n    \n    NSString* expectedResult = @\"iw_mul_30\";\n    \n    // When\n    conSut = [CLDConditionExpression initialWidth];\n    [conSut multipleByString: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_initialHeightDivide_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"ih_div_30\";\n    \n    // When\n    conSut = [CLDConditionExpression initialHeight];\n    [conSut divideByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_aspectRatioPower_shouldCreateValidExpression {\n        \n    // Given\n    float input = 30.3;\n    \n    NSString* expectedResult = @\"ar_pow_30.3\";\n    \n    // When\n    conSut = [CLDConditionExpression aspectRatio];\n    [conSut powerByFloat: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_initialAspectRatioAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"iar_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression initialAspectRatio];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_pageCountAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"pc_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression pageCount];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_faceCountAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"fc_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression faceCount];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_tagsAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"tags_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression tags];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_pageXOffsetAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"px_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression pageXOffset];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_pageYOffsetAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"py_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression pageYOffset];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_illustrationScoreAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"ils_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression illustrationScore];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_currentPageIndexAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"cp_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression currentPageIndex];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_durationAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"du_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression duration];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingConditionExpression_initialDurationAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"idu_add_30\";\n    \n    // When\n    conSut = [CLDConditionExpression initialDuration];\n    [conSut addByInt: input];\n    \n    NSString* actualResult = [conSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n\n// MARK: - asParams\n- (void)test_asParams_initialDurationAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSDictionary* expectedResult = @{@\"idu\":@\"add_30\"};\n    \n    // When\n    conSut = [CLDConditionExpression initialDuration];\n    [conSut addByInt: input];\n    \n    NSDictionary* actualResult = [conSut asParams];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue(actualResult.count == 1 && expectedResult.count == 1, \"Calling get asString should return the expect string\");\n    XCTAssertTrue([actualResult.allKeys[0] isEqualToString: expectedResult.allKeys[0]], \"Calling get asString should return the expect string\");\n    XCTAssertTrue([actualResult.allValues[0] isEqualToString: expectedResult.allValues[0]], \"Calling get asString should return the expect string\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDConditionExpressionTests/CLDConditionExpressionTests.swift",
    "content": "//\n//  CLDConditionExpressionTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass CLDConditionExpressionTests: BaseTestCase {\n    \n    var sut : CLDConditionExpression!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - test initilization methods - empty\n    func test_init_emptyInputParamaters_shouldStoreEmptyProperties() {\n        \n        // Given\n        let name = String()\n        \n        // When\n        sut = CLDConditionExpression()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil currentKey  property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil currentValue property\")\n        XCTAssertEqual(sut.currentKey, name, \"Name property should be equal to name\")\n        XCTAssertEqual(sut.currentValue, String(), \"Initilized object should contain an empty string as currentValue property\")\n    }\n    \n    // MARK: - test initilization methods - value\n    func test_init_emptyNameParamater_shouldStoreEmptyNameProperty() {\n        \n        // Given\n        let name  = String()\n        let value = \"alue\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(value)\")\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil currentKey  property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil currentValue property\")\n        XCTAssertEqual(sut.currentValue, value, \"Initilized object should contain an empty string as value property\")\n    }\n    \n    func test_init_validStringParamatersAndNoNamePrefix_shouldStoreValidProperties() {\n        \n        // Given\n        let name  = \"name\"\n        let value = \"alue\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(value)\")\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, name, \"currentKey should be equal to name\")\n        XCTAssertEqual(sut.currentValue, value, \"Initilized object should contain a string as value property\")\n    }\n    \n    func test_init_validStringParamaters_shouldStoreValidProperties() {\n        \n        // Given\n        let name  = \"w\"\n        let value = \"* 2\"\n        let valueResult = \"*_2\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(value)\")\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, name, \"currentKey should be equal to name\")\n        XCTAssertEqual(sut.currentValue, valueResult, \"Initilized object should contain a string as valueResult property\")\n    }\n    \n    \n    // MARK: - test class methods\n    func test_width_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"w\"\n        \n        // When\n        sut = CLDConditionExpression.width()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_height_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"h\"\n        \n        // When\n        sut = CLDConditionExpression.height()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_initialWidth_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"iw\"\n        \n        // When\n        sut = CLDConditionExpression.initialWidth()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_initialHeight_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"ih\"\n        \n        // When\n        sut = CLDConditionExpression.initialHeight()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_aspectRatio_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"ar\"\n        \n        // When\n        sut = CLDConditionExpression.aspectRatio()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_initialAspectRatio_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"iar\"\n        \n        // When\n        sut = CLDConditionExpression.initialAspectRatio()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_pageCount_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"pc\"\n        \n        // When\n        sut = CLDConditionExpression.pageCount()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_faceCount_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"fc\"\n        \n        // When\n        sut = CLDConditionExpression.faceCount()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_tags_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"tags\"\n        \n        // When\n        sut = CLDConditionExpression.tags()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_pageXOffset_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"px\"\n        \n        // When\n        sut = CLDConditionExpression.pageXOffset()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_pageYOffset_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"py\"\n        \n        // When\n        sut = CLDConditionExpression.pageYOffset()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_illustrationScore_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"ils\"\n        \n        // When\n        sut = CLDConditionExpression.illustrationScore()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_currentPageIndex_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"cp\"\n        \n        // When\n        sut = CLDConditionExpression.currentPageIndex()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    // MARK: - test instance method\n    // MARK: - add\n    func test_addInt_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = 20\n        let expectedValueResult = \"add_20\"\n        // When\n        \n        sut = CLDConditionExpression.width().add(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_addInt_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = 20\n        \n        let expectedValueResult = \"width_add_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").add(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_addFloat_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = Float(30.3)\n        let expectedValueResult = \"add_30.3\"\n        // When\n        \n        sut = CLDConditionExpression.width().add(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_addFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"width_add_30.3\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").add(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - subtract\n    func test_subtractInt_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = 20\n        let expectedValueResult = \"sub_20\"\n        // When\n        \n        sut = CLDConditionExpression.width().subtract(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_subtractInt_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = 20\n        \n        let expectedValueResult = \"width_sub_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").subtract(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_subtractFloat_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = Float(30.3)\n        let expectedValueResult = \"sub_30.3\"\n        // When\n        \n        sut = CLDConditionExpression.width().subtract(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_subtractFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"width_sub_30.3\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").subtract(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - multiple\n    func test_multipleInt_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = 20\n        let expectedValueResult = \"mul_20\"\n        // When\n        \n        sut = CLDConditionExpression.width().multiple(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_multipleInt_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = 20\n        \n        let expectedValueResult = \"width_mul_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").multiple(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_multipleFloat_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = Float(30.3)\n        let expectedValueResult = \"mul_30.3\"\n        // When\n        \n        sut = CLDConditionExpression.width().multiple(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_multipleFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"width_mul_30.3\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").multiple(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - divide\n    func test_divideInt_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = 20\n        let expectedValueResult = \"div_20\"\n        // When\n        \n        sut = CLDConditionExpression.width().divide(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_divideInt_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = 20\n        \n        let expectedValueResult = \"width_div_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_divideFloat_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = Float(30.3)\n        let expectedValueResult = \"div_30.3\"\n        // When\n        \n        sut = CLDConditionExpression.width().divide(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_divideFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"width_div_30.3\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - power\n    func test_powerInt_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = 20\n        let expectedValueResult = \"pow_20\"\n        \n        // When\n        sut = CLDConditionExpression.width().power(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_powerInt_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = 20\n        \n        let expectedValueResult = \"width_pow_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").power(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_powerFloat_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = Float(30.3)\n        let expectedValueResult = \"pow_30.3\"\n        \n        // When\n        sut = CLDConditionExpression.width().power(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_powerFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"width_pow_30.3\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").power(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_powerFloat_shouldAppendValidValueToVariable() {\n        //    $big_$small_pow_1.5/c_fill,w_$big,h_$small_add_20\n        // Given\n        let initialValue = \"$big $small ^  1.5\"\n        let expectedValueResult = \"$big_$small_pow_1.5\"\n        \n        // When\n        sut = CLDConditionExpression(value: initialValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_powerString_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"width_pow_30.3\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").power(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - equal\n    func test_equalFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let equalValue = Float(10.1)\n        let expectedValueResult = \"width_div_30.3_eq_10.1\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).equal(to: equalValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_equalString_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let equalValue = \"initialHeight\"\n        let expectedValueResult = \"width_div_30.3_eq_initialHeight\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).equal(to: equalValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_equalBaseExpression_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let equalValue = CLDExpression.initialHeight()\n        let expectedValueResult = \"width_div_30.3_eq_ih\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).equal(to: equalValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_equalExpression_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expressionValue = CLDExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"width_div_30.3_eq_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).equal(to: expressionValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - notEqual\n    func test_notEqual_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        let unequalValue = Float(10.1)\n        \n        let expectedValueResult = \"width_div_30.3_ne_10.1\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).notEqual(to: unequalValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_notEqual_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let unequalValue = \"initialHeight\"\n        let expectedValueResult = \"width_div_30.3_ne_initialHeight\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).notEqual(to: unequalValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_notEqual_baseExpressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let unequalValue = CLDExpression.initialHeight()\n        let expectedValueResult = \"width_div_30.3_ne_ih\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).notEqual(to: unequalValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_notEqual_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expressionValue = CLDExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"width_div_30.3_ne_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).notEqual(to: expressionValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n\n    // MARK: - less\n    func test_less_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let lessValue = \"initialHeight\"\n        let expectedValueResult = \"width_div_30.3_lt_initialHeight\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).less(then: lessValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_less_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let lessValue = 100\n        let expectedValueResult = \"width_div_30.3_lt_100\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).less(then: lessValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_less_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let lessValue: Float = 100.1\n        let expectedValueResult = \"width_div_30.3_lt_100.1\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).less(then: lessValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_less_baseExpressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let lessValue = CLDExpression.initialHeight()\n        let expectedValueResult = \"width_div_30.3_lt_ih\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).less(then: lessValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_less_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expressionValue = CLDExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"width_div_30.3_lt_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).less(then: expressionValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - greater\n    func test_greater_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let greaterValue = \"initialHeight\"\n        let expectedValueResult = \"width_div_30.3_gt_initialHeight\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).greater(then: greaterValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_greater_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let greaterValue = 100\n        let expectedValueResult = \"width_div_30.3_gt_100\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).greater(then: greaterValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_greater_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let greaterValue: Float = 100.1\n        let expectedValueResult = \"width_div_30.3_gt_100.1\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).greater(then: greaterValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_greater_baseExpressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let greaterValue = CLDExpression.initialHeight()\n        let expectedValueResult = \"width_div_30.3_gt_ih\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).greater(then: greaterValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_greater_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expressionValue = CLDExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"width_div_30.3_gt_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).greater(then: expressionValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - lessOrEqual\n    func test_lessOrEqual_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let lessOrEqualValue = \"initialHeight\"\n        let expectedValueResult = \"width_div_30.3_lte_initialHeight\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).lessOrEqual(to: lessOrEqualValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_lessOrEqual_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let lessOrEqualValue = 100\n        let expectedValueResult = \"width_div_30.3_lte_100\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).lessOrEqual(to: lessOrEqualValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_lessOrEqual_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let lessOrEqualValue: Float = 100.1\n        let expectedValueResult = \"width_div_30.3_lte_100.1\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).lessOrEqual(to: lessOrEqualValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_lessOrEqual_baseExpressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let lessOrEqualValue = CLDExpression.initialHeight()\n        let expectedValueResult = \"width_div_30.3_lte_ih\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).lessOrEqual(to: lessOrEqualValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_lessOrEqual_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expressionValue = CLDExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"width_div_30.3_lte_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).lessOrEqual(to: expressionValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - greaterOrEqual\n    func test_greaterOrEqual_stringValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let greaterOrEqualValue = \"initialHeight\"\n        let expectedValueResult = \"width_div_30.3_gte_initialHeight\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).greaterOrEqual(to: greaterOrEqualValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_greaterOrEqual_intValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let greaterOrEqualValue = 100\n        let expectedValueResult = \"width_div_30.3_gte_100\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).greaterOrEqual(to: greaterOrEqualValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_greaterOrEqual_floatValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let greaterOrEqualValue: Float = 100.1\n        let expectedValueResult = \"width_div_30.3_gte_100.1\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).greaterOrEqual(to: greaterOrEqualValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_greaterOrEqual_baseExpressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let greaterOrEqualValue = CLDExpression.initialHeight()\n        let expectedValueResult = \"width_div_30.3_gte_ih\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).greaterOrEqual(to: greaterOrEqualValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_greaterOrEqual_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expressionValue = CLDExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"width_div_30.3_gte_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(initialValue)\").divide(by: value).greaterOrEqual(to: expressionValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - or\n    func test_or_shouldAppendValidValue() {\n        \n        // Given\n        let value = \"width > 200\"\n        let expectedValueResult = \">_200_or\"\n        \n        // When\n        sut = CLDConditionExpression(value: value).or()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - and\n    func test_and_shouldAppendValidValue() {\n        \n        // Given\n        let value = \"width > 200\"\n        let expectedValueResult = \">_200_and\"\n        \n        // When\n        sut = CLDConditionExpression(value: value).and()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - value\n    func test_value_empty_shouldNotAppendValue() {\n        \n        // Given\n        let value = \"\"\n        let expectedValueResult = \"\"\n        \n        // When\n        sut = CLDConditionExpression().value(value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_valueOnEmptyKey_validStringParamaters_shouldAppendValidValue() {\n        \n        // Given\n        let value = \"width > 200\"\n        let expectedValueResult = \">_200\"\n        \n        // When\n        sut = CLDConditionExpression().value(value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_valueValidKey_validStringParamaters_shouldAppendValidValue() {\n        \n        // Given\n        let value = \"> 200\"\n        let initialValue = \"width\"\n        let expectedValueResult = \">_200\"\n        \n        // When\n        sut = CLDConditionExpression(value: initialValue).value(value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_value_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let initialValue = \"width\"\n        \n        let expressionValue = CLDExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression(value: initialValue).value(expressionValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_valueAfterAnd_shouldAppendValidValue() {\n        \n        // Given\n        let initialValue = \"width > 200\"\n        let value = \"height > 200\"\n        let expectedValueResult = \">_200_and_h_gt_200\"\n        \n        // When\n        sut = CLDConditionExpression(value: initialValue).and().value(value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - inside\n    func test_inside_empty_shouldNotAppendValue() {\n        \n        // Given\n        let tag = \"!myTag2!\"\n        let expectedValueResult = \"\"\n        \n        // When\n        sut = CLDConditionExpression().value(tag).inside(\"\")\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_inside_validStringParamaters_shouldAppendValidValue() {\n        \n        // Given\n        let tag = \"!myTag2!\"\n        let expectedValueResult = \"in_tags\"\n        \n        // When\n        sut = CLDConditionExpression().value(tag).inside(\"tags\")\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_inside_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let tag = \"!myTag2!\"\n        \n        let expressionValue = CLDExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"in_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().value(tag).inside(expressionValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - notInside\n    func test_notInside_empty_shouldNotAppendValue() {\n        \n        // Given\n        let tag = \"!myTag2!\"\n        let expectedValueResult = \"\"\n        \n        // When\n        sut = CLDConditionExpression().value(tag).notInside(\"\")\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_notInside_validStringParamaters_shouldAppendValidValue() {\n        \n        // Given\n        let tag = \"!myTag2!\"\n        let expectedValueResult = \"nin_tags\"\n        \n        // When\n        sut = CLDConditionExpression().value(tag).notInside(\"tags\")\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_notInside_expressionValue_shouldAppendValidValue() {\n        \n        // Given\n        let tag = \"!myTag2!\"\n        \n        let expressionValue = CLDExpression.initialHeight().add(by: 20)\n        let expectedValueResult = \"nin_ih_add_20\"\n        \n        // When\n        sut = CLDConditionExpression().value(tag).notInside(expressionValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - test asString()\n    func test_asString_emptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let value = String()\n        let expectedResult = String()\n        \n        // When\n        sut = CLDConditionExpression(value: value)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString on an empty CLDConditionExpression, should return an empty string\")\n    }\n    \n    func test_asString_validParamaters_shouldReturnValidString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"* 200 / faceCount\"\n        let expectedResult  = \"iw_mul_200_div_fc\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(value)\")\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString on a CLDConditionExpression, should return a string\")\n    }\n    \n    func test_asString_emptyKey_shouldReturnEmptyString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"* 200 / faceCount\"\n        let expectedValue   = \"*_200_/_faceCount\"\n        let expectedResult  = \"\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(value)\")\n        sut.currentKey = \"\"\n        \n        let actualResult = sut.asString()\n        let actualValue  = sut.currentValue\n        \n        // Then\n        XCTAssertEqual(actualValue,  expectedValue, \"Calling asString on a CLDConditionExpression, should return a string\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString on a CLDConditionExpression, should return an empty string\")\n    }\n    \n    func test_asString_extraSpacesStringParamaters_shouldReturnValidString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"*      200\"\n        let expectedResult  = \"iw_mul_200\"\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(value)\")\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString, should remove extra dashes/spaces\")\n    }\n    \n    // MARK: - test asParams()\n    func test_asParams_emptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let value = String()\n        let expectedResult = [String:String]()\n        \n        // When\n        sut = CLDConditionExpression(value: value)\n        \n        let actualResult = sut.asParams()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asParams, should build a paramater representation\")\n    }\n    \n    func test_asParams_validParamaters_shouldReturnValidString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"* 200 / faceCount\"\n        let expectedResult  = [\"iw\":\"mul_200_div_fc\"]\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(value)\")\n        \n        let actualResult = sut.asParams()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asParams, should build a paramater representation\")\n    }\n    \n    func test_asParam_emptyKey_shouldReturnEmptyString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"* 200 / faceCount\"\n        let expectedValue   = \"*_200_/_faceCount\"\n        let expectedResult  = [String:String]()\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(value)\")\n        sut.currentKey = \"\"\n        \n        let actualResult = sut.asParams()\n        let actualValue  = sut.currentValue\n        \n        // Then\n        XCTAssertEqual(actualValue,  expectedValue, \"Calling asString on a CLDConditionExpression, should return a string\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString on a CLDConditionExpression, should return an empty string\")\n    }\n    \n    func test_asParams_extraSpacesStringParamaters_shouldReturnValidString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"*      200\"\n        let expectedResult  = [\"iw\":\"mul_200\"]\n        \n        // When\n        sut = CLDConditionExpression(value: \"\\(name) \\(value)\")\n        \n        let actualResult = sut.asParams()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString, should remove extra dashes/spaces\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDExpressionTests/CLDExpressionTests.m",
    "content": "//\n//  ObjcCLDExpressionTests.m\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"ObjcBaseTestCase.h\"\n\n@interface ObjcCLDExpressionTests : ObjcBaseTestCase\n\n@end\n\n@implementation ObjcCLDExpressionTests\n\nCLDExpression *expSut;\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n}\n\n- (void)tearDown {\n    [super tearDown];\n    expSut = nil;\n}\n\n// MARK: - creatingExpression\n- (void)test_creatingExpression_widthAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"w_add_30\";\n    \n    // When\n    expSut = [CLDExpression width];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_heightSubtract_shouldCreateValidExpression {\n        \n    // Given\n    float input = 30.3;\n    \n    NSString* expectedResult = @\"h_sub_30.3\";\n    \n    // When\n    expSut = [CLDExpression height];\n    [expSut subtractByFloat: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_initialWidthMultiple_shouldCreateValidExpression {\n        \n    // Given\n    NSString* input = @\"30\";\n    \n    NSString* expectedResult = @\"iw_mul_30\";\n    \n    // When\n    expSut = [CLDExpression initialWidth];\n    [expSut multipleByString: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_initialHeightDivide_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"ih_div_30\";\n    \n    // When\n    expSut = [CLDExpression initialHeight];\n    [expSut divideByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_aspectRatioPower_shouldCreateValidExpression {\n        \n    // Given\n    float input = 30.3;\n    \n    NSString* expectedResult = @\"ar_pow_30.3\";\n    \n    // When\n    expSut = [CLDExpression aspectRatio];\n    [expSut powerByFloat: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_initialAspectRatioAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"iar_add_30\";\n    \n    // When\n    expSut = [CLDExpression initialAspectRatio];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_pageCountAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"pc_add_30\";\n    \n    // When\n    expSut = [CLDExpression pageCount];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_faceCountAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"fc_add_30\";\n    \n    // When\n    expSut = [CLDExpression faceCount];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_tagsAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"tags_add_30\";\n    \n    // When\n    expSut = [CLDExpression tags];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_pageXOffsetAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"px_add_30\";\n    \n    // When\n    expSut = [CLDExpression pageXOffset];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_pageYOffsetAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"py_add_30\";\n    \n    // When\n    expSut = [CLDExpression pageYOffset];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_illustrationScoreAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"ils_add_30\";\n    \n    // When\n    expSut = [CLDExpression illustrationScore];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_currentPageIndexAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"cp_add_30\";\n    \n    // When\n    expSut = [CLDExpression currentPageIndex];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_durationAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"du_add_30\";\n    \n    // When\n    expSut = [CLDExpression duration];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n- (void)test_creatingExpression_initialDurationAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSString* expectedResult = @\"idu_add_30\";\n    \n    // When\n    expSut = [CLDExpression initialDuration];\n    [expSut addByInt: input];\n    \n    NSString* actualResult = [expSut asString];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n\n// MARK: - asParams\n- (void)test_asParams_initialDurationAdd_shouldCreateValidExpression {\n        \n    // Given\n    int input = 30;\n    \n    NSDictionary* expectedResult = @{@\"idu\":@\"add_30\"};\n    \n    // When\n    expSut = [CLDExpression initialDuration];\n    [expSut addByInt: input];\n    \n    NSDictionary* actualResult = [expSut asParams];\n    \n    // Then\n    XCTAssertNotNil(actualResult, \"Initilized object should contain a none nil name property\");\n    XCTAssertTrue(actualResult.count == 1 && expectedResult.count == 1, \"Calling get asString should return the expect string\");\n    XCTAssertTrue([actualResult.allKeys[0] isEqualToString: expectedResult.allKeys[0]], \"Calling get asString should return the expect string\");\n    XCTAssertTrue([actualResult.allValues[0] isEqualToString: expectedResult.allValues[0]], \"Calling get asString should return the expect string\");\n}\n\n\n@end\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDExpressionTests/CLDExpressionTests.swift",
    "content": "//\n//  CLDExpressionTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass CLDExpressionTests: BaseTestCase {\n    \n    var sut : CLDExpression!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - test initilization methods - empty\n    func test_init_emptyInputParamaters_shouldStoreEmptyProperties() {\n        \n        // Given\n        let name = String()\n        \n        // When\n        sut = CLDExpression()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil currentKey  property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil currentValue property\")\n        XCTAssertEqual(sut.currentKey, name, \"Name property should be equal to name\")\n        XCTAssertEqual(sut.currentValue, String(), \"Initilized object should contain an empty string as currentValue property\")\n    }\n    \n    // MARK: - test initilization methods - value\n    func test_init_emptyNameParamater_shouldStoreEmptyNameProperty() {\n        \n        // Given\n        let name  = String()\n        let value = \"alue\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(value)\")\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil currentKey  property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil currentValue property\")\n        XCTAssertEqual(sut.currentValue, value, \"Initilized object should contain an empty string as value property\")\n    }\n    \n    func test_init_validStringParamatersAndNoNamePrefix_shouldStoreValidProperties() {\n        \n        // Given\n        let name  = \"name\"\n        let value = \"alue\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(value)\")\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, name, \"currentKey should be equal to name\")\n        XCTAssertEqual(sut.currentValue, value, \"Initilized object should contain a string as value property\")\n    }\n    \n    func test_init_validStringParamaters_shouldStoreValidProperties() {\n        \n        // Given\n        let name  = \"w\"\n        let value = \"* 2\"\n        let valueResult = \"*_2\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(value)\")\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, name, \"currentKey should be equal to name\")\n        XCTAssertEqual(sut.currentValue, valueResult, \"Initilized object should contain a string as valueResult property\")\n    }\n    \n    // MARK: - test class methods\n    func test_width_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"w\"\n        \n        // When\n        sut = CLDExpression.width()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_height_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"h\"\n        \n        // When\n        sut = CLDExpression.height()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_initialWidth_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"iw\"\n        \n        // When\n        sut = CLDExpression.initialWidth()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_initialHeight_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"ih\"\n        \n        // When\n        sut = CLDExpression.initialHeight()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_aspectRatio_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"ar\"\n        \n        // When\n        sut = CLDExpression.aspectRatio()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_initialAspectRatio_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"iar\"\n        \n        // When\n        sut = CLDExpression.initialAspectRatio()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_pageCount_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"pc\"\n        \n        // When\n        sut = CLDExpression.pageCount()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_faceCount_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"fc\"\n        \n        // When\n        sut = CLDExpression.faceCount()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_tags_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"tags\"\n        \n        // When\n        sut = CLDExpression.tags()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_pageXOffset_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"px\"\n        \n        // When\n        sut = CLDExpression.pageXOffset()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_pageYOffset_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"py\"\n        \n        // When\n        sut = CLDExpression.pageYOffset()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_illustrationScore_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"ils\"\n        \n        // When\n        sut = CLDExpression.illustrationScore()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    func test_currentPageIndex_shouldStoreValidKey() {\n        \n        // Given\n        let expectedResult = \"cp\"\n        \n        // When\n        sut = CLDExpression.currentPageIndex()\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentKey, expectedResult, \"currentKey should be equal to expectedResult\")\n    }\n    \n    // MARK: - test instance method\n    func test_addInt_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = 20\n        let expectedValueResult = \"add_20\"\n        // When\n        \n        sut = CLDExpression.width().add(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_addInt_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = 20\n        \n        let expectedValueResult = \"width_add_20\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").add(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_addFloat_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = Float(30.3)\n        let expectedValueResult = \"add_30.3\"\n        // When\n        \n        sut = CLDExpression.width().add(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_addFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"width_add_30.3\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").add(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_addString_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"width_add_30.3\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").add(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_subtractInt_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = 20\n        let expectedValueResult = \"sub_20\"\n        // When\n        \n        sut = CLDExpression.width().subtract(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_subtractInt_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = 20\n        \n        let expectedValueResult = \"width_sub_20\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").subtract(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_subtractFloat_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = Float(30.3)\n        let expectedValueResult = \"sub_30.3\"\n        // When\n        \n        sut = CLDExpression.width().subtract(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_subtractFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"width_sub_30.3\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").subtract(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_subtractString_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"width_sub_30.3\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").subtract(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_multipleInt_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = 20\n        let expectedValueResult = \"mul_20\"\n        // When\n        \n        sut = CLDExpression.width().multiple(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_multipleInt_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = 20\n        \n        let expectedValueResult = \"width_mul_20\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").multiple(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_multipleFloat_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = Float(30.3)\n        let expectedValueResult = \"mul_30.3\"\n        // When\n        \n        sut = CLDExpression.width().multiple(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_multipleFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"width_mul_30.3\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").multiple(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_multipleString_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"width_mul_30.3\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").multiple(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_divideInt_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = 20\n        let expectedValueResult = \"div_20\"\n        \n        // When\n        \n        sut = CLDExpression.width().divide(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_divideInt_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = 20\n        \n        let expectedValueResult = \"width_div_20\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").divide(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_divideFloat_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = Float(30.3)\n        let expectedValueResult = \"div_30.3\"\n        // When\n        \n        sut = CLDExpression.width().divide(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_divideFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"width_div_30.3\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").divide(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_divideString_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"width_div_30.3\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").divide(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - power\n    func test_powerInt_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = 20\n        let expectedValueResult = \"pow_20\"\n        \n        // When\n        sut = CLDExpression.width().power(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_powerInt_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = 20\n        \n        let expectedValueResult = \"width_pow_20\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").power(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_powerFloat_shouldStoreValidFirstValue() {\n        \n        // Given\n        let value = Float(30.3)\n        let expectedValueResult = \"pow_30.3\"\n        \n        // When\n        sut = CLDExpression.width().power(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_powerFloat_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = Float(30.3)\n        \n        let expectedValueResult = \"width_pow_30.3\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").power(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_powerFloat_shouldAppendValidValueToVariable() {\n\n        // Given\n        let initialValue = \"$big $small ^  1.5\"\n        let expectedValueResult = \"$big_$small_pow_1.5\"\n        \n        // When\n        sut = CLDExpression(value: initialValue)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.asString(), expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    func test_powerString_shouldAppendValidValue() {\n        \n        // Given\n        let name = \"height\"\n        let initialValue = \"width\"\n        let value = \"30.3\"\n        \n        let expectedValueResult = \"width_pow_30.3\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(initialValue)\").power(by: value)\n        \n        // Then\n        XCTAssertNotNil(sut.currentKey, \"Initilized object should contain a none nil key property\")\n        XCTAssertNotNil(sut.currentValue, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.currentValue, expectedValueResult, \"currentValue should be equal to expectedValueResult\")\n    }\n    \n    // MARK: - test asString()\n    func test_asString_emptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let value = String()\n        let expectedResult = String()\n        \n        // When\n        sut = CLDExpression(value: value)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString on an empty CLDExpression, should return an empty string\")\n    }\n    \n    func test_asString_validParamaters_shouldReturnValidString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"* 200 / faceCount\"\n        let expectedResult  = \"iw_mul_200_div_fc\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(value)\")\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString on a CLDExpression, should return a string\")\n    }\n    \n    func test_asString_extraSpacesStringParamaters_shouldReturnValidString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"*           200\"\n        let expectedResult  = \"iw_mul_200\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(value)\")\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString, should remove extra dashes/spaces\")\n    }\n    \n    func test_asString_complexStringValue_shouldReturnValidString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"200 * $width\"\n        let expectedResult  = \"iw_200_mul_$width\"\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(value)\")\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString, should remove extra dashes/spaces\")\n    }\n    \n    // MARK: - test asParams()\n    func test_asParams_emptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let value = String()\n        let expectedResult = [String:String]()\n        \n        // When\n        sut = CLDExpression(value: value)\n        \n        let actualResult = sut.asParams()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asParams, should build a paramater representation\")\n    }\n    \n    func test_asParams_validParamaters_shouldReturnValidString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"* 200 / faceCount\"\n        let expectedResult  = [\"iw\":\"mul_200_div_fc\"]\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(value)\")\n        \n        let actualResult = sut.asParams()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asParams, should build a paramater representation\")\n    }\n    \n    func test_asParams_extraSpacesStringParamaters_shouldReturnValidString() {\n        \n        // Given\n        let name            = \"initialWidth\"\n        let value           = \"*        200\"\n        let expectedResult  = [\"iw\":\"mul_200\"]\n        \n        // When\n        sut = CLDExpression(value: \"\\(name) \\(value)\")\n        \n        let actualResult = sut.asParams()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asParams, should remove extra dashes/spaces\")\n    }\n\n    func test_powerString_shouldAppendValidValuex() {\n       // Given\n       let name = \"$________height\"\n       let initialValue = \"$_____width\"\n       let value = \"30.3\"\n\n       let expectedValueResult = \"$_height_$_width_pow_30.3\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name) \\(initialValue)\").power(by: value)\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionNumber() {\n       // Given\n       let name = 10\n       let expectedValueResult = \"10\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionSingleSpace_underscore() {\n       // Given\n       let name = \" \"\n       let expectedValueResult = \"_\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionBlankString_underscore() {\n       // Given\n       let name = \"  \"\n       let expectedValueResult = \"_\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionUnderscore_underscore() {\n       // Given\n       let name = \"_\"\n       let expectedValueResult = \"_\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionUnderscores_underscore() {\n       // Given\n       let name = \"___\"\n       let expectedValueResult = \"_\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionUnderscoresAndSpaces_underscore() {\n       // Given\n       let name = \" _ __  _\"\n       let expectedValueResult = \"_\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionArbitraryText_isNotAffected() {\n       // Given\n       let name = \"foobar\"\n       let expectedValueResult = \"foobar\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDoubleAmpersand_replacedWithAndOperator() {\n       // Given\n       let name = \"foo && bar\"\n       let expectedValueResult = \"foo_and_bar\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDoubleAmpersandWithNoSpaceAtEnd_isNotAffected() {\n       // Given\n       let name = \"foo&&bar\"\n       let expectedValueResult = \"foo&&bar\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionWidth_recognizedAsVariableAndReplacedWithW() {\n       // Given\n       let name = \"width\"\n       let expectedValueResult = \"w\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionInitialAspectRatio_recognizedAsVariableAndReplacedWithW() {\n       // Given\n       let name = \"width\"\n       let expectedValueResult = \"w\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDollarWidth_recognizedAsUserVariableAndNotAffected() {\n       // Given\n       let name = \"$width\"\n       let expectedValueResult = \"$width\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDollarInitialAspectRatio_recognizedAsUserVariableAndAsVariableReplacedWithAr() {\n       // Given\n       let name = \"$initial_aspect_ratio\"\n       let expectedValueResult = \"$initial_ar\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDollarMyWidth_recognizedAsUserVariableAndNotAffected() {\n       // Given\n       let name = \"$mywidth\"\n       let expectedValueResult = \"$mywidth\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDollarWidthWidth_recognizedAsUserVariableAndNotAffected() {\n       // Given\n       let name = \"$widthwidth\"\n       let expectedValueResult = \"$widthwidth\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDollarUnderscoreWidth_recognizedAsUserVariableAndNotAffected() {\n       // Given\n       let name = \"$_width\"\n       let expectedValueResult = \"$_width\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDollarUnderscoreX2Width_recognizedAsUserVariableAndNotAffected() {\n       // Given\n       let name = \"$__width\"\n       let expectedValueResult = \"$_width\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDollarX2Width_recognizedAsUserVariableAndNotAffected() {\n       // Given\n       let name = \"$\\\\$width\"\n       let expectedValueResult = \"$\\\\$width\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDoesntReplaceVariable_1() {\n       // Given\n       let name = \"$height\"\n       let value = \"100\"\n       let expectedValueResult = \"$height_100\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name) \\(value)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDoesntReplaceVariable_2() {\n       // Given\n       let name = \"$heightt\"\n       let value = \"100\"\n       let expectedValueResult = \"$heightt_100\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name) \\(value)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDoesntReplaceVariable_3() {\n       // Given\n       let name = \"$\\\\$height\"\n       let value = \"100\"\n       let expectedValueResult = \"$\\\\$height_100\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name) \\(value)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDoesntReplaceVariable_4() {\n       // Given\n       let name = \"$heightmy\"\n       let value = \"100\"\n       let expectedValueResult = \"$heightmy_100\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name) \\(value)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDoesntReplaceVariable_5() {\n       // Given\n       let name = \"$myheight\"\n       let value = \"100\"\n       let expectedValueResult = \"$myheight_100\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name) \\(value)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDoesntReplaceVariable_6() {\n       // Given\n       let name = \"$heightheight\"\n       let value = \"100\"\n       let expectedValueResult = \"$heightheight_100\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name) \\(value)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDoesntReplaceVariable_7() {\n       // Given\n       let name = \"$theheight\"\n       let value = \"100\"\n       let expectedValueResult = \"$theheight_100\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name) \\(value)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n\n   func testExpressionDoesntReplaceVariable_8() {\n       // Given\n       let name = \"$________height\"\n       let value = \"100\"\n       let expectedValueResult = \"$_height_100\"\n\n       // When\n       sut = CLDExpression(value: \"\\(name) \\(value)\")\n\n       // Then\n       XCTAssertEqual(sut.asString(), expectedValueResult, \"string should be equal to expectedValueResult\")\n   }\n}\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDTransformationTests/CLDTransformationBaselineTests.swift",
    "content": "//\n//  CLDTransformationBaselineTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\n// MARK: - CLDTransformationBaselineTests\nclass CLDTransformationBaselineTests: BaseTestCase {\n    \n    var sut : CLDTransformation!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = CLDTransformation()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - ifCondition with String\n    func test_ifCondition_emptyStringProperty_shouldNotStoreNewParam() {\n        \n        // Given\n        let stringInput = String()\n        \n        // When\n        sut.ifCondition(stringInput)\n        \n        let actualResult = sut.ifParam!\n        \n        // Then\n        XCTAssertTrue(actualResult.isEmpty, \"Empty expression should not be stored in params\")\n    }\n    // MARK: -\n    func test_WithLiteral()\n    {\n        var transformation = CLDTransformation().ifCondition(\"w_lt_200\").setCrop(\"fill\").setHeight(120).setWidth(80)\n        var sTransform = transformation.asString()!\n        XCTAssertEqual(sTransform.firstIndex(of: \"if\"), 0, \"should include the if parameter as the first component in the transformation string\")\n        XCTAssertEqual(\"if_w_lt_200,c_fill,h_120,w_80\", sTransform, \"should be proper transformation string\")\n        \n        transformation = CLDTransformation().setCrop(\"fill\").setHeight(120).ifCondition(\"w_lt_200\").setWidth(80)\n        sTransform = transformation.asString()!\n        XCTAssertEqual(sTransform.firstIndex(of: \"if\"), 0, \"should include the if parameter as the first component in the transformation string\")\n        XCTAssertEqual(\"if_w_lt_200,c_fill,h_120,w_80\", sTransform, \"components should be in proper order\")\n        \n        transformation = CLDTransformation().ifCondition(\"w_lt_200\").setCrop(\"fill\").setHeight(120).setWidth(80)\n            .chain().ifCondition(\"w_gt_400\").setCrop(\"fit\").setHeight(150).setWidth(150)\n            .chain().setEffect(\"sepia\")\n        sTransform = transformation.asString()!\n        XCTAssertEqual(\"if_w_lt_200,c_fill,h_120,w_80/if_w_gt_400,c_fit,h_150,w_150/e_sepia\", sTransform, \"should allow multiple conditions when chaining transformations\")\n    }\n    \n    func test_LiteralWithSpaces()\n    {\n        let transformation = CLDTransformation().ifCondition(\"w < 200\").setCrop(\"fill\").setHeight(120).setWidth(80)\n        let sTransform = transformation.asString()!\n        XCTAssertEqual(\"if_w_lt_200,c_fill,h_120,w_80\", sTransform, \"should translate operators\")\n    }\n    \n    func test_EndIf()\n    {\n        let transformation = CLDTransformation().ifCondition(\"w_lt_200\").setCrop(\"fill\").setHeight(120).setWidth(80).setEffect(\"sharpen\")\n            .chain().setEffect(\"brightness\", param: \"50\")\n            .chain().setEffect(\"shadow\").setColor(\"red\")\n            .endIf()\n        \n        let sTransform = transformation.asString()!\n        XCTAssertTrue(sTransform.hasSuffix(\"if_end\"), \"should include the if_end as the last parameter in its component\")\n        XCTAssertEqual(\"if_w_lt_200/c_fill,e_sharpen,h_120,w_80/e_brightness:50/co_red,e_shadow/if_end\", sTransform, \"should be proper transformation string\")\n    }\n    \n    func test_IfElse()\n    {\n        var transformation = CLDTransformation(input: [\n            CLDTransformation().ifCondition(\"w_lt_200\").setCrop(\"fill\").setHeight(120).setWidth(80),\n            CLDTransformation().ifElse().setCrop(\"fill\").setHeight(90).setWidth(100)\n        ])\n        \n        var sTransform = transformation.asString()!\n        XCTAssertEqual(\"if_w_lt_200,c_fill,h_120,w_80/if_else,c_fill,h_90,w_100\", sTransform, \"should support if_else with transformation parameters\")\n        \n        transformation = CLDTransformation(input: [\n            CLDTransformation().ifCondition(\"w_lt_200\"),\n            CLDTransformation().setCrop(\"fill\").setHeight(120).setWidth(80),\n            CLDTransformation().ifElse(),\n            CLDTransformation().setCrop(\"fill\").setHeight(90).setWidth(100)\n        ])\n        sTransform = transformation.asString()!\n        \n        XCTAssertTrue(sTransform.contains(\"/if_else/\"), \"if_else should be without any transformation parameters\")\n        XCTAssertEqual(\"if_w_lt_200/c_fill,h_120,w_80/if_else/c_fill,h_90,w_100\", sTransform, \"should be proper transformation string\")\n    }\n    \n    func test_ChainedConditions()\n    {\n        var transformation = CLDTransformation().ifCondition().aspectRatio(\"gt\", \"3:4\").then().setWidth(100).setCrop(\"scale\")\n        XCTAssertEqual(\"if_ar_gt_3:4,c_scale,w_100\", transformation.asString()!, \"passing an operator and a value adds a condition\")\n        \n        transformation = CLDTransformation().ifCondition().aspectRatio(\"gt\", \"3:4\").and().width(\"gt\", 100).then().setWidth(50).setCrop(\"scale\")\n        XCTAssertEqual(\"if_ar_gt_3:4_and_w_gt_100,c_scale,w_50\", transformation.asString()!, \"should chaining condition with `and`\")\n        \n        transformation = CLDTransformation().ifCondition().aspectRatio(\"gt\", \"3:4\").and().width(\"gt\", 100).or().width(\"gt\", 200).then().setWidth(50).setCrop(\"scale\")\n        XCTAssertEqual(\"if_ar_gt_3:4_and_w_gt_100_or_w_gt_200,c_scale,w_50\", transformation.asString()!, \"should chain conditions with `or`\")\n        \n        transformation = CLDTransformation().ifCondition().aspectRatio(\">\", \"3:4\").and().width(\"<=\", 100).or().width(\"gt\", 200).then().setWidth(50).setCrop(\"scale\")\n        XCTAssertEqual(\"if_ar_gt_3:4_and_w_lte_100_or_w_gt_200,c_scale,w_50\", transformation.asString()!, \"should translate operators\")\n        \n        transformation = CLDTransformation().ifCondition().aspectRatio(\">\", \"3:4\").and().width(\"<=\", 100).or().width(\">\", 200).then().setWidth(50).setCrop(\"scale\")\n        XCTAssertEqual(\"if_ar_gt_3:4_and_w_lte_100_or_w_gt_200,c_scale,w_50\", transformation.asString()!, \"should translate operators\")\n        \n        transformation = CLDTransformation().ifCondition().aspectRatio(\">=\", \"3:4\").and().pageCount(\">=\", 100).or().pageCount(\"!=\", 0).then().setWidth(50).setCrop(\"scale\")\n        XCTAssertEqual(\"if_ar_gte_3:4_and_pc_gte_100_or_pc_ne_0,c_scale,w_50\", transformation.asString()!, \"should translate operators\")\n        \n        transformation = CLDTransformation().ifCondition().aspectRatio(\"gt\", \"3:4\").and().initialHeight(\">\", 100).and().initialWidth(\"<\", 500).then().setWidth(100).setCrop(\"scale\")\n        XCTAssertEqual(\"if_ar_gt_3:4_and_ih_gt_100_and_iw_lt_500,c_scale,w_100\", transformation.asString()!, \"passing an operator and a value adds a condition\")\n        \n        transformation = CLDTransformation().ifCondition().initialDuration(\">\", 30).and().initialHeight(\">\", 100).and().initialWidth(\"<\", 500).then().setWidth(100).setCrop(\"scale\")\n        XCTAssertEqual(\"if_idu_gt_30_and_ih_gt_100_and_iw_lt_500,c_scale,w_100\", transformation.asString()!, \"passing an operator and a value adds a condition\")\n        \n        transformation = CLDTransformation().ifCondition().duration(\"<\", 30).and().initialHeight(\">\", 100).and().initialWidth(\"<\", 500).then().setWidth(100).setCrop(\"scale\")\n        XCTAssertEqual(\"if_du_lt_30_and_ih_gt_100_and_iw_lt_500,c_scale,w_100\", transformation.asString()!, \"passing an operator and a value adds a condition\")\n    }\n    \n    func test_ShouldSupportAndTranslateOperators()\n    {\n        let allOperators = \"if_\" +\n            \"w_eq_0_and\" +\n            \"_h_ne_0_or\" +\n            \"_ar_lt_0_and\" +\n            \"_pc_gt_0_and\" +\n            \"_fc_lte_0_and\" +\n            \"_w_gte_0\" +\n        \",e_grayscale\"\n        \n        XCTAssertEqual(allOperators, CLDTransformation().ifCondition()\n            .width(\"=\", 0).and()\n            .height(\"!=\", 0).or()\n            .aspectRatio(\"<\", \"0\").and()\n            .pageCount(\">\", 0).and()\n            .faceCount(\"<=\", 0).and()\n            .width(\">=\", 0)\n            .then().setEffect(\"grayscale\").asString()!, \"should support and translate operators:  '=', '!=', '<', '>', '<=', '>=', '&&', '||'\")\n        \n        XCTAssertEqual(allOperators, CLDTransformation().ifCondition(\"w = 0 && height != 0 || aspectRatio < 0 and pageCount > 0 and faceCount <= 0 and width >= 0\")\n            .setEffect(\"grayscale\")\n            .asString()!)\n    }\n    \n    func test_EndIf2()\n    {\n        var transformation = CLDTransformation().ifCondition().width(\"gt\", 100).and().width(\"lt\", 200).then().setWidth(50).setCrop(\"scale\").endIf()\n        XCTAssertEqual(\"if_w_gt_100_and_w_lt_200/c_scale,w_50/if_end\", transformation.asString()!, \"should serialize to 'if_end'\")\n        \n        transformation = CLDTransformation().ifCondition().width(\"gt\", 100).and().width(\"lt\", 200).then().setWidth(50).setCrop(\"scale\").endIf()\n        XCTAssertEqual(\"if_w_gt_100_and_w_lt_200/c_scale,w_50/if_end\", transformation.asString()!, \"force the if clause to be chained\")\n        \n        transformation = CLDTransformation().ifCondition().width(\"gt\", 100).and().width(\"lt\", 200).then().setWidth(50).setCrop(\"scale\").ifElse().setWidth(100).setCrop(\"crop\").endIf()\n        XCTAssertEqual(\"if_w_gt_100_and_w_lt_200/c_scale,w_50/if_else/c_crop,w_100/if_end\", transformation.asString()!, \"force the if_else clause to be chained\")\n    }\n    \n    func test_TestExpressionOperators()\n    {\n        let transformationStr = \"$foo_10,$foostr_!my:str:ing!/if_fc_gt_2_and\" +\n            \"_pc_lt_300_or\" +\n            \"_!myTag1!_in_tags_and\" +\n            \"_!myTag2!_nin_tags_and\" +\n            \"_w_gte_200_and\" +\n            \"_h_eq_$foo_and\" +\n            \"_w_ne_$foo_mul_2_and\" +\n            \"_h_lt_$foo_or\" +\n            \"_w_lte_500_and\" +\n            \"_ils_lt_0_and\" +\n            \"_cp_eq_10_and\" +\n            \"_px_lt_300_and\" +\n            \"_py_lt_300_and\" +\n            \"_py_ne_400_and\" +\n            \"_ar_gt_3:4_and\" +\n            \"_iar_gt_3:4_and\" +\n            \"_h_lt_iw_div_2_add_1_and\" +\n            \"_w_lt_ih_sub_$foo_and\" +\n            \"_du_eq_$foo_and\" +\n            \"_du_ne_$foo_and\" +\n            \"_du_lt_30_and\" +\n            \"_du_lte_$foo_and\" +\n            \"_du_gt_30_and\" +\n            \"_du_gte_$foo_and\" +\n            \"_idu_eq_$foo_and\" +\n            \"_idu_ne_$foo_and\" +\n            \"_idu_lt_30_and\" +\n            \"_idu_lte_$foo_and\" +\n            \"_idu_gt_30_and\" +\n            \"_idu_gte_$foo\" +\n        \"/c_scale,l_$foostr,w_$foo_mul_200_div_fc/if_end\"\n        \n        let transformation = CLDTransformation()\n            .setVariable(\"$foo\", int: 10)\n            .setVariable(\"$foostr\", values: [\"my\", \"str\", \"ing\"])\n            .chain()\n            .ifCondition(\n                CLDConditionExpression.faceCount().greater(then: 2)\n                    .and().value(CLDConditionExpression.pageCount().less(then: 300))\n                    .or(\"!myTag1!\").inside(CLDConditionExpression.tags())\n                    .and(\"!myTag2!\").notInside(CLDConditionExpression.tags())\n                    .and().value(CLDConditionExpression.width().greaterOrEqual(to: 200))\n                    .and().value(CLDConditionExpression.height().equal(to: \"$foo\"))\n                    .and().value(CLDConditionExpression.width().notEqual(to: \"$foo\").multiple(by: 2))\n                    .and().value(CLDConditionExpression.height().less(then: \"$foo\"))\n                    .or().value(CLDConditionExpression.width().lessOrEqual(to: 500))\n                    .and().value(CLDConditionExpression.illustrationScore().less(then: 0))\n                    .and().value(CLDConditionExpression.currentPageIndex().equal(to: 10))\n                    .and().value(CLDConditionExpression.pageXOffset().less(then: 300))\n                    .and().value(CLDConditionExpression.pageYOffset().less(then: 300))\n                    .and().value(CLDConditionExpression.pageYOffset().notEqual(to: 400))\n                    .and().value(CLDConditionExpression.aspectRatio().greater(then: \"3:4\"))\n                    .and().value(CLDConditionExpression.initialAspectRatio().greater(then: \"3:4\"))\n                    .and().value(CLDConditionExpression.height().less(then: CLDConditionExpression.initialWidth().divide(by: 2).add(by: 1)))\n                    .and().value(CLDConditionExpression.width().less(then: CLDConditionExpression.initialHeight().subtract(by: \"$foo\")))\n                    .and().value(CLDConditionExpression.duration().equal(to: \"$foo\"))\n                    .and().value(CLDConditionExpression.duration().notEqual(to: \"$foo\"))\n                    .and().value(CLDConditionExpression.duration().less(then: 30))\n                    .and().value(CLDConditionExpression.duration().lessOrEqual(to: \"$foo\"))\n                    .and().value(CLDConditionExpression.duration().greater(then: 30))\n                    .and().value(CLDConditionExpression.duration().greaterOrEqual(to: \"$foo\"))\n                    .and().value(CLDConditionExpression.initialDuration().equal(to: \"$foo\"))\n                    .and().value(CLDConditionExpression.initialDuration().notEqual(to: \"$foo\"))\n                    .and().value(CLDConditionExpression.initialDuration().less(then: 30))\n                    .and().value(CLDConditionExpression.initialDuration().lessOrEqual(to: \"$foo\"))\n                    .and().value(CLDConditionExpression.initialDuration().greater(then: 30))\n                    .and().value(CLDConditionExpression.initialDuration().greaterOrEqual(to: \"$foo\")))\n            .setCrop(\"scale\")\n            .setWidth(CLDConditionExpression(value: \"$foo * 200 / faceCount\"))\n            .setOverlay(\"$foostr\")\n            .endIf()\n        \n        XCTAssertEqual(transformationStr, transformation.asString()!)\n    }\n    \n    func test_TestExpressionOperatorsWithValues()\n    {\n        let transformationStr = \"$foo_10,$foostr_!my:str:ing!/if_fc_gt_2_and\" +\n            \"_pc_lt_300_or\" +\n            \"_!myTag1!_in_tags_and\" +\n            \"_!myTag2!_nin_tags_and\" +\n            \"_w_gte_200_and\" +\n            \"_h_eq_$foo_and\" +\n            \"_w_ne_$foo_mul_2_and\" +\n            \"_h_lt_$foo_or\" +\n            \"_w_lte_500_and\" +\n            \"_ils_lt_0_and\" +\n            \"_cp_eq_10_and\" +\n            \"_px_lt_300_and\" +\n            \"_py_lt_300_and\" +\n            \"_py_ne_400_and\" +\n            \"_ar_gt_3:4_and\" +\n            \"_iar_gt_3:4_and\" +\n            \"_h_lt_iw_div_2_add_1_and\" +\n            \"_w_lt_ih_sub_$foo\" +\n        \"/c_scale,l_$foostr,w_$foo_mul_200_div_fc/if_end\"\n\n        let transformation = CLDTransformation()\n            .setVariable(\"$foo\", int: 10)\n            .setVariable(\"$foostr\", values: [\"my\", \"str\", \"ing\"])\n            .chain()\n            .ifCondition(\n                CLDConditionExpression.faceCount().greater(then: 2)\n                    .and(CLDConditionExpression.pageCount().less(then: 300))\n                    .or(\"!myTag1!\").inside(CLDConditionExpression.tags())\n                    .and(\"!myTag2!\").notInside(CLDConditionExpression.tags())\n                    .and(CLDConditionExpression.width().greaterOrEqual(to: 200))\n                    .and(CLDConditionExpression.height().equal(to: \"$foo\"))\n                    .and(CLDConditionExpression.width().notEqual(to: \"$foo\").multiple(by: 2))\n                    .and(CLDConditionExpression.height().less(then: \"$foo\"))\n                    .or(CLDConditionExpression.width().lessOrEqual(to: 500))\n                    .and(CLDConditionExpression.illustrationScore().less(then: 0))\n                    .and(CLDConditionExpression.currentPageIndex().equal(to: 10))\n                    .and(CLDConditionExpression.pageXOffset().less(then: 300))\n                    .and(CLDConditionExpression.pageYOffset().less(then: 300))\n                    .and(CLDConditionExpression.pageYOffset().notEqual(to: 400))\n                    .and(CLDConditionExpression.aspectRatio().greater(then: \"3:4\"))\n                    .and(CLDConditionExpression.initialAspectRatio().greater(then: \"3:4\"))\n                    .and(CLDConditionExpression.height().less(then: CLDConditionExpression.initialWidth().divide(by: 2).add(by: 1)))\n                    .and(CLDConditionExpression.width().less(then: CLDConditionExpression.initialHeight().subtract(by: \"$foo\")))\n        )\n            .setCrop(\"scale\")\n            .setWidth(CLDConditionExpression(value: \"$foo * 200 / faceCount\"))\n            .setOverlay(\"$foostr\")\n            .endIf()\n        \n        XCTAssertEqual(transformationStr, transformation.asString()!)\n    }\n    \n    func test_TestExpressionsClone()\n    {\n        let transformationStr = \"if_pc_lt_300/c_scale/if_end\"\n        let expression = CLDConditionExpression.pageCount().less(then: 300)\n        \n        let transformation = CLDTransformation()\n            .ifCondition(expression)\n            .setCrop(\"scale\")\n            .endIf()\n        \n        let clone = transformation\n        expression.greater(then: 2)\n        \n        XCTAssertEqual(transformationStr, clone.asString()!)\n    }\n    \n    func test_TestShouldNotChangeVariableNamesWhenTheyNamedAfterKeyword()\n    {\n        let transformation = CLDTransformation()\n            .setVariable(\"$width\", int: 10)\n            .chain()\n            .setWidth(\"$width + 10 + width\")\n        let sTransform = transformation.asString()!\n        \n        XCTAssertEqual(\"$width_10/w_$width_add_10_add_w\", sTransform)\n    }\n    \n    func test_TestShouldSupportPowOperator()\n    {\n        let transformation = CLDTransformation().setVariables([\n            CLDVariable(name: \"$small\", value: 150),\n            CLDVariable(name: \"$big\"  , value: \"$small ^ 1.5\"),\n        ])\n        let sTransform = transformation.asString()!\n        \n        XCTAssertEqual(\"$small_150,$big_$small_pow_1.5\", sTransform)\n    }\n}\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDTransformationTests/CLDTransformationConditionsTests.swift",
    "content": "//\n//  CLDTransformationConditionsTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\n// MARK: - ConditionalCLDTransformationTests\nclass CLDTransformationConditionsTests: BaseTestCase {\n    \n    var sut : CLDTransformation!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = CLDTransformation()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - ifCondition with String\n    func test_ifCondition_emptyStringProperty_shouldNotStoreNewParam() {\n        \n        // Given\n        let stringInput = String()\n        \n        // When\n        sut.ifCondition(stringInput)\n        \n        let actualResult = sut.ifParam!\n        \n        // Then\n        XCTAssertTrue(actualResult.isEmpty, \"Empty expression should not be stored in params\")\n    }\n    \n    func test_ifCondition_spacedStringProperty_shouldStoreValidString() {\n        \n        // Given\n        let stringInput = \"w < 200\"\n        \n        let expectedResult = \"w_lt_200\"\n        \n        // When\n        sut.ifCondition(stringInput)\n        \n        let actualResult = sut.ifParam!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"valid value should be stored\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for valid value should return the expected result\")\n    }\n    \n    // MARK: - ifCondition with CLDConditionExpression\n    func test_ifCondition_emptyConditionProperty_shouldNotStoreNewParam() {\n        \n        // Given\n        let conditionObject = CLDConditionExpression()\n        \n        // When\n        sut.ifCondition(conditionObject)\n        \n        let actualResult = sut.ifParam!\n        \n        // Then\n        XCTAssertTrue(actualResult.isEmpty, \"Empty expression should not be stored in params\")\n    }\n    \n    func test_ifCondition_conditionProperty_shouldStoreValidString() {\n        \n        // Given\n        let initialValue = \"width < 200\"\n        let conditionObject = CLDConditionExpression(value: initialValue)\n        \n        let expectedResult = \"w_lt_200\"\n        \n        // When\n        sut.ifCondition(conditionObject)\n        \n        let actualResult = sut.ifParam!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"valid value should be stored\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for valid value should return the expected result\")\n    }\n    \n    // MARK: - asString()\n    func test_ifConditionAsString_emptyConditionProperty_shouldStoreNil() {\n        \n        // Given\n        let conditionObject = CLDConditionExpression()\n        \n        // When\n        sut.ifCondition(conditionObject)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertNil(actualResult, \"Empty expression should not return from asString()\")\n    }\n    \n    func test_ifConditionAsString_emptyStringProperty_shouldStoreNil() {\n        \n        // Given\n        let emptyString = String()\n        \n        // When\n        sut.ifCondition(emptyString)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertNil(actualResult, \"Empty expression should not return from asString()\")\n    }\n    \n    func test_ifConditionAsString_spacedStringProperty_shouldReturnValidString() {\n        \n        // Given\n        let stringInput = \"w < 200\"\n        \n        let expectedResult = \"if_w_lt_200\"\n        \n        // When\n        sut.ifCondition(stringInput)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString should return the expected result\")\n    }\n    \n    func test_ifConditionAsString_extraSpacedStringProperty_shouldReturnValidString() {\n        \n        // Given\n        let stringInput = \"w <       200\"\n        \n        let expectedResult = \"if_w_lt_200\"\n        \n        // When\n        sut.ifCondition(stringInput)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString, should remove extra dashes/spaces\")\n    }\n    \n    func test_ifConditionAsString_stringProperty_shouldReturnValidString() {\n        \n        // Given\n        let stringInput = \"w_lt_200\"\n        \n        let expectedResult = \"if_w_lt_200\"\n        \n        // When\n        sut.ifCondition(stringInput)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString should return the expected result\")\n    }\n    \n    func test_ifCondition_orderedStringConditionAndMultiProperties_shouldReturnValidString() {\n        \n        // Given\n        let conditionStringInput = \"w_lt_200\"\n        \n        let expectedResult = \"if_w_lt_200,c_fill,h_120,w_80\"\n        \n        // When\n        sut.ifCondition(conditionStringInput).setCrop(.fill).setHeight(120).setWidth(80)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertTrue(actualResult.hasPrefix(\"if\"), \"ifCondition should appear at the beginning of the trasformation string\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString should return the expected result\")\n    }\n    \n    func test_ifCondition_unorderedStringConditionAndMultiProperties_shouldReturnValidOrderedString() {\n        \n        // Given\n        let conditionStringInput = \"w_lt_200\"\n        \n        let expectedResult = \"if_w_lt_200,c_fill,h_120,w_80\"\n        \n        // When\n        sut.setCrop(.fill).setHeight(120).ifCondition(conditionStringInput).setWidth(80)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertTrue(actualResult.hasPrefix(\"if\"), \"ifCondition should appear at the beginning of the trasformation string\")\n        XCTAssertEqual(actualResult, expectedResult, \"components should be in proper order\")\n    }\n    \n    // MARK: - multi transformations condition\n    func test_multiTransformationIfCondition_StringConditionAndMultiProperties_shouldReturnValidOrderedString() {\n        \n        // Given\n        let conditionStringInput1 = \"w_lt_200\"\n        let conditionStringInput2 = \"w_gt_400\"\n        \n        let expectedResult = \"if_w_lt_200,c_fill,h_120,w_80/if_w_gt_400,c_fit,h_150,w_150/e_sepia\"\n        \n        // When\n        sut.ifCondition(conditionStringInput1).setCrop(.fill).setHeight(120).setWidth(80)\n            .chain().ifCondition(conditionStringInput2).setCrop(.fit).setHeight(150).setWidth(150)\n            .chain().setEffect(.sepia)\n        \n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertTrue(actualResult.hasPrefix(\"if\"), \"ifCondition should appear at the beginning of the trasformation string\")\n        XCTAssertEqual(actualResult, expectedResult, \"should allow multiple conditions when chaining transformations\")\n    }\n    \n    func test_multiTransformationUnorderedIfCondition_StringConditionAndMultiProperties_shouldReturnValidOrderedString() {\n        \n        // Given\n        let conditionStringInput1 = \"w_lt_200\"\n        let conditionStringInput2 = \"w_gt_400\"\n        \n        let expectedResult = \"if_w_lt_200,c_fill,h_120,w_80/if_w_gt_400,c_fit,h_150,w_150/e_sepia\"\n        \n        // When\n        sut.setCrop(.fill).ifCondition(conditionStringInput1).setHeight(120).setWidth(80)\n            .chain().setCrop(.fit).setHeight(150).ifCondition(conditionStringInput2).setWidth(150)\n            .chain().setEffect(.sepia)\n        \n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertTrue(actualResult.hasPrefix(\"if\"), \"ifCondition should appear at the beginning of the trasformation string\")\n        XCTAssertEqual(actualResult, expectedResult, \"should order multiple conditions when chaining transformations\")\n    }\n    \n    // MARK: - operators\n    func test_ifCondition_specialOperators_shouldReturnValidString() {\n        \n        // Given\n        let initialValue    = \"width > 200\"\n        let valueHeight     = \"height > 200\"\n        let valueWidth      = \"width < 300\"\n        let expectedResult  = \"if_w_gt_200_and_h_gt_200_or_w_lt_300\"\n        \n        let conditionObject = CLDConditionExpression(value: initialValue).and().value(valueHeight).or().value(valueWidth)\n        \n        // When\n        sut.ifCondition(conditionObject)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertTrue(actualResult.hasPrefix(\"if\"), \"ifCondition should appear at the beginning of the trasformation string\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString should return the expected result\")\n    }\n    \n    // MARK: - ifElse\n    func test_ifElse_shouldStoreNewParam() {\n        \n        // Given\n        let expectedResult  = \"else\"\n        \n        // When\n        sut.ifElse()\n        \n        let actualResult = sut.ifParam!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"valid value should be stored\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for valid value should return the expected result\")\n    }\n    \n    func test_ifElse_shouldReturnValidString() {\n        \n        // Given\n        let expectedResult  = \"if_else\"\n        \n        // When\n        sut.ifElse()\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"valid value should be stored\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for valid value should return the expected result\")\n    }\n    \n    func test_ifElse_multiProperties_shouldReturnValidString() {\n        \n        // Given\n        let conditionStringInput = \"w_lt_200\"\n        \n        let expectedResult = \"if_w_lt_200,c_fill,h_120,w_80/if_else,c_fit,h_150,w_150/e_sepia\"\n        \n        // When\n        sut.ifCondition(conditionStringInput).setCrop(.fill).setHeight(120).setWidth(80)\n            .ifElse().setCrop(.fit).setHeight(150).setWidth(150)\n            .chain().setEffect(.sepia)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertTrue(actualResult.hasPrefix(\"if\"), \"ifCondition should appear at the beginning of the trasformation string\")\n        XCTAssertEqual(actualResult, expectedResult, \"should order multiple conditions when chaining transformations\")\n    }\n        \n    // MARK: - endIf\n    func test_endIf_emptyTransformation_shouldReturnNil() {\n        \n        // When\n        sut.endIf()\n        \n        let actualResult = sut.ifParam\n        \n        // Then\n        XCTAssertNil(actualResult, \"endIf should not stand alone\")\n    }\n    \n    func test_endIf_multiProperties_shouldReturnValidString() {\n        \n        // Given\n        let conditionStringInput = \"w_lt_200\"\n        \n        let expectedResult = \"if_w_lt_200/c_fill,h_120,w_80/if_else/c_fit,h_150,w_150/e_sepia/if_end\"\n        \n        // When\n        sut.ifCondition(conditionStringInput).setCrop(.fill).setHeight(120).setWidth(80)\n            .ifElse().setCrop(.fit).setHeight(150).setWidth(150)\n            .chain().setEffect(.sepia).endIf()\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertTrue(actualResult.hasSuffix(\"if_end\"), \"asString() return value should have an 'if_end' suffix\")\n        XCTAssertEqual(actualResult, expectedResult, \"endIf() should separate the first ifCondition to a new transformation\")\n    }\n    \n    func test_endIf_callEndIfTwice_shouldReturnValidString() {\n        \n        // Given\n        let conditionStringInput = \"w_lt_200\"\n        \n        let expectedResult = \"if_w_lt_200/c_fill,h_120,w_80/if_else/c_fit,h_150/if_end/w_150/e_sepia/if_end\"\n        \n        // When\n        sut.ifCondition(conditionStringInput).setCrop(.fill).setHeight(120).setWidth(80)\n            .ifElse().setCrop(.fit).setHeight(150).endIf().setWidth(150)\n            .chain().setEffect(.sepia).endIf()\n        \n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertTrue(actualResult.hasSuffix(\"if_end\"), \"asString() return value should have an 'if_end' suffix\")\n        XCTAssertEqual(actualResult, expectedResult, \"calling endIf() twice should return a valid string (although this probebly shouldn't happen)\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDTransformationTests/CLDTransformationExpressionsTests.swift",
    "content": "//\n//  CLDTransformationExpressionsTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass CLDTransformationExpressionsTests: BaseTestCase {\n     \n    var sut : CLDTransformation!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = CLDTransformation()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    \n    // MARK: - test set expression using get property\n    func test_setWidth_emptyInputParamaters_shouldNotStoreNewVariable() {\n        \n        // Given\n        let input       = String()\n        let expression  = CLDExpression(value: input)\n        \n        // When\n        sut.setWidth(expression)\n        \n        let actualResult = sut.width!\n        \n        // Then\n        XCTAssertTrue(actualResult.isEmpty, \"Empty expression should not be stored in params\")\n    }\n    \n    func test_setWidth_inputExpression_shouldStoreNewValue() {\n        \n        // Given\n        let input       = \"initialHeight * 2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"ih_mul_2\"\n        \n        // When\n        sut.setWidth(expression)\n        \n        let actualResult = sut.width!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"width should stored new value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get width should return its value\")\n    }\n    \n    func test_setHeight_emptyInputParamaters_shouldNotStoreNewVariable() {\n        \n        // Given\n        let input       = String()\n        let expression  = CLDExpression(value: input)\n        \n        // When\n        sut.setHeight(expression)\n        \n        let actualResult = sut.height!\n        \n        // Then\n        XCTAssertTrue(actualResult.isEmpty, \"Empty expression should not be stored in params\")\n    }\n    \n    func test_setHeight_inputExpression_shouldStoreNewValue() {\n        \n        // Given\n        let input       = \"initialHeight * 2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"ih_mul_2\"\n        \n        // When\n        sut.setHeight(expression)\n        \n        let actualResult = sut.height!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"x should stored new value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get height should return its value\")\n    }\n    \n    \n    func test_setX_emptyInputParamaters_shouldNotStoreNewVariable() {\n        \n        // Given\n        let input       = String()\n        let expression  = CLDExpression(value: input)\n        \n        // When\n        sut.setX(expression)\n        \n        let actualResult = sut.x!\n        \n        // Then\n        XCTAssertTrue(actualResult.isEmpty, \"Empty expression should not be stored in params\")\n    }\n    \n    func test_setX_inputExpression_shouldStoreNewValue() {\n        \n        // Given\n        let input       = \"initialHeight * 2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"ih_mul_2\"\n        \n        // When\n        sut.setX(expression)\n        \n        let actualResult = sut.x!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"x should stored new value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get x should return its value\")\n    }\n    \n    func test_setStartOffset_emptyInputParamaters_shouldNotStoreNewVariable() {\n        \n        // Given\n        let input       = String()\n        let expression  = CLDExpression(value: input)\n        \n        // When\n        sut.setStartOffset(expression)\n        \n        let actualResult = sut.startOffset!\n        \n        // Then\n        XCTAssertTrue(actualResult.isEmpty, \"Empty expression should not be stored in params\")\n    }\n    \n    func test_setStartOffset_inputExpression_shouldStoreNewValue() {\n        \n        // Given\n        let input       = \"duration - 3\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"du_sub_3\"\n        \n        // When\n        sut.setStartOffset(expression)\n        \n        let actualResult = sut.startOffset!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"actualResult should not be empty\")\n        XCTAssertEqual(actualResult, expectedResult, \"actualResult and expectedResult should be equal\")\n    }\n    \n    func test_setEndOffset_emptyInputParamaters_shouldNotStoreNewVariable() {\n        \n        // Given\n        let input       = String()\n        let expression  = CLDExpression(value: input)\n        \n        // When\n        sut.setEndOffset(expression)\n        \n        let actualResult = sut.endOffset!\n        \n        // Then\n        XCTAssertTrue(actualResult.isEmpty, \"Empty expression should not be stored in params\")\n    }\n    \n    func test_setEndOffset_inputExpression_shouldStoreNewValue() {\n        \n        // Given\n        let input       = \"duration - 3\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"du_sub_3\"\n        \n        // When\n        sut.setEndOffset(expression)\n        \n        let actualResult = sut.endOffset!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"actualResult should not be empty\")\n        XCTAssertEqual(actualResult, expectedResult, \"actualResult and expectedResult should be equal\")\n    }\n    \n    func test_setY_emptyInputParamaters_shouldNotStoreNewVariable() {\n        \n        // Given\n        let input       = String()\n        let expression  = CLDExpression(value: input)\n        \n        // When\n        sut.setY(expression)\n        \n        let actualResult = sut.y!\n        \n        // Then\n        XCTAssertTrue(actualResult.isEmpty, \"Empty expression should not be stored in params\")\n    }\n    \n    func test_setY_inputExpression_shouldStoreNewValue() {\n        \n        // Given\n        let input       = \"initialHeight * 2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"ih_mul_2\"\n        \n        // When\n        sut.setY(expression)\n        \n        let actualResult = sut.y!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"y should stored new value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get y should return its value\")\n    }\n    \n    func test_setRadius_emptyInputParamaters_shouldNotStoreNewVariable() {\n        \n        // Given\n        let input       = String()\n        let expression  = CLDExpression(value: input)\n        \n        // When\n        sut.setRadius(expression)\n        \n        let actualResult = sut.radius!\n        \n        // Then\n        XCTAssertTrue(actualResult.isEmpty, \"Empty expression should not be stored in params\")\n    }\n    \n    func test_setRadius_inputExpression_shouldStoreNewValue() {\n        \n        // Given\n        let input       = \"initialHeight * 2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"ih_mul_2\"\n        \n        // When\n        sut.setRadius(expression)\n        \n        let actualResult = sut.radius!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"y should stored new value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get y should return its value\")\n    }\n    \n    // MARK: - test asString() on empty expression\n    \n    func test_asString_expressionWidthWithEmptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let value       = String()\n        let expression  = CLDExpression(value: value)\n        \n        // When\n        sut.setWidth(expression)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertNil(actualResult, \"Empty CLDExpression should not be stored in params\")\n    }\n    \n    func test_asString_expressionHeightWithEmptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let value       = String()\n        let expression  = CLDExpression(value: value)\n        \n        // When\n        sut.setHeight(expression)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertNil(actualResult, \"Empty CLDExpression should not be stored in params\")\n    }\n    \n    func test_asString_expressionXWithEmptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let value       = String()\n        let expression  = CLDExpression(value: value)\n        \n        // When\n        sut.setX(expression)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertNil(actualResult, \"Empty CLDExpression should not be stored in params\")\n    }\n    \n    func test_asString_expressionYWithEmptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let value       = String()\n        let expression  = CLDExpression(value: value)\n        \n        // When\n        sut.setY(expression)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertNil(actualResult, \"Empty CLDExpression should not be stored in params\")\n    }\n    \n    func test_asString_expressionRadiusWithEmptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let value       = String()\n        let expression  = CLDExpression(value: value)\n        \n        // When\n        sut.setRadius(expression)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertNil(actualResult, \"Empty CLDExpression should not be stored in params\")\n    }\n    \n    // MARK: - test asString() on expression\n    func test_asString_expressionOnWidth_shouldReturnValidString() {\n        \n        // Given\n        let input       = \"initialHeight * 2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"w_ih_mul_2\"\n        \n        // When\n        sut.setWidth(expression)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get asString should return its value\")\n    }\n    \n    func test_asString_expressionOnHeight_shouldReturnValidString() {\n        \n        // Given\n        let input       = \"initialHeight * 2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"h_ih_mul_2\"\n        \n        // When\n        sut.setHeight(expression)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get asString should return its value\")\n    }\n    \n    func test_asString_expressionOnX_shouldReturnValidString() {\n        \n        // Given\n        let input       = \"initialHeight * 2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"x_ih_mul_2\"\n        \n        // When\n        sut.setX(expression)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get asString should return its value\")\n    }\n    \n    func test_asString_expressionOnY_shouldReturnValidString() {\n        \n        // Given\n        let input       = \"initialHeight * 2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"y_ih_mul_2\"\n        \n        // When\n        sut.setY(expression)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get asString should return its value\")\n    }\n    \n    func test_asString_expressionOnRadius_shouldReturnValidString() {\n        \n        // Given\n        let input       = \"initialHeight * 2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"r_ih_mul_2\"\n        \n        // When\n        sut.setRadius(expression)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get asString should return its value\")\n    }\n    \n    func test_asString_extraSpacedExpression_shouldReturnValidString() {\n        \n        // Given\n        let input       = \"initialHeight *      2\"\n        let expression  = CLDExpression(value: input)\n        \n        let expectedResult = \"r_ih_mul_2\"\n        \n        // When\n        sut.setRadius(expression)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString should remove extra spaces\")\n    }\n    \n    func test_asString_expressionOnTwoProperties_shouldReturnValidString() {\n        \n        // Given\n        let widthInput          = \"initialHeight * 2\"\n        let widthExpression     = CLDExpression(value: widthInput)\n        let radiusInput         = \"initialWidth * 2\"\n        let radiusExpression    = CLDExpression(value: radiusInput)\n        \n        let expectedResult = \"r_iw_mul_2,w_ih_mul_2\"\n        \n        // When\n        sut.setRadius(radiusExpression)\n        sut.setWidth(widthExpression)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertFalse(actualResult.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult, expectedResult, \"Calling get asString should return its value\")\n    }\n    \n    func test_complexVariablesAtExpressionStart_shouldRetainNames() {\n        \n        // Given\n        let variable       = CLDVariable(name: \"$width\", value: 10)\n        let expectedResult = \"$width_10/w_$width_add_10_add_w\"\n        \n        // When\n        sut.setVariable(variable)\n        sut.chain()\n        sut.setWidth(\"$width + 10 + width\")\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertFalse(actualResult!.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult!, expectedResult, \"Calling get asString should return its value\")\n    }\n    func test_complexVariablesAtExpressionEnd_shouldRetainNames() {\n        \n        // Given\n        let variable       = CLDVariable(name: \"$width\", value: 10)\n        let expectedResult = \"$width_10/w_w_add_10_add_$width\"\n        \n        // When\n        sut.setVariable(variable)\n        sut.chain()\n        sut.setWidth(\"width + 10 + $width\")\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertFalse(actualResult!.isEmpty, \"asString should stored valid value\")\n        XCTAssertEqual(actualResult!, expectedResult, \"Calling get asString should return its value\")\n    }\n    \n    // MARK: - chained conditions\n    func test_chainedConditions_then_shouldReturnValidString() {\n        \n        // Given\n        let expectedResult = \"if_w_gt_200,c_scale,w_100\"\n        \n        // When\n        sut.ifCondition().width(\">\", 200).then().setCrop(.scale).setWidth(100)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"chained conditions should create the expected result\")\n    }\n    func test_chainedConditions_ifElse_shouldReturnValidString() {\n        \n        // Given\n        let expectedResult = \"if_w_gt_200,c_fit,w_200/if_else,c_scale,w_100\"\n        \n        // When\n        sut.ifCondition().width(\">\", 200).then().setCrop(.fit).setWidth(200).ifElse().setCrop(.scale).setWidth(100)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"chained conditions should create the expected result\")\n    }\n    func test_chainedConditions_endIf_shouldReturnValidString() {\n        \n        // Given\n        let expectedResult = \"if_w_gt_200/c_scale,w_100/if_end\"\n        \n        // When\n        sut.ifCondition().width(\">\", 200).then().setCrop(.scale).setWidth(100).endIf()\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"chained conditions should create the expected result\")\n    }\n    func test_chainedConditions_thenInFunc_shouldReturnValidString() {\n        \n        // Given\n        let condition  = CLDConditionExpression.width().greater(then: 100)\n        let expression = CLDExpression.height().multiple(by: 10)\n        \n        let expectedResult = \"if_w_gt_100,h_mul_10\"\n        \n        // When\n        sut.ifCondition(condition, then: expression)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"chained conditions should create the expected result\")\n    }\n\n}\n\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDTransformationTests/CLDTransformationTests.m",
    "content": "//\n//  ObjcCLDTransformationTests.m\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"ObjcBaseTestCase.h\"\n\n@interface ObjcCLDTransformationTests : ObjcBaseTestCase\n@property (nonatomic, strong, nullable) CLDTransformation *sut;\n@end\n\n@implementation ObjcCLDTransformationTests\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n    self.sut = [[CLDTransformation alloc] init];\n}\n\n- (void)tearDown {\n    [super tearDown];\n    self.sut = nil;\n}\n\n// MARK: - complexConditionExpression\n- (void)test_complexTransformations_shouldCreateValidString {\n        \n    // Given\n    NSString * expectedResult = [self getExpectedResultToComplexConditionTest];\n    \n    // When\n    self.sut = [self.sut setVariable:@\"$foo\" intValue: 10];\n    self.sut = [self.sut setVariable:@\"$foostr\" valuesArray: @[@\"my\", @\"str\", @\"ing\"]];\n    self.sut = [self.sut chain];\n    self.sut = [self.sut ifCondition: [self getIfConditionForComplexConditionTest]];\n    self.sut = [self.sut setCrop: @\"scale\"];\n    \n    CLDConditionExpression *conditionForWidth = [[CLDConditionExpression alloc] initWithValue: @\"$foo * 200 / faceCount\"];\n    self.sut = [self.sut setWidthWithExpression: conditionForWidth];\n    self.sut = [self.sut setOverlay: @\"$foostr\"];\n    self.sut = [self.sut endIf];\n    \n    NSString * actualResult = [self.sut asString];\n    \n    // Then\n    XCTAssertTrue([actualResult isEqualToString: expectedResult], \"Calling get asString should return the expect string\");\n}\n\n-(CLDConditionExpression*)getIfConditionForComplexConditionTest {\n    CLDConditionExpression* condition = [[CLDConditionExpression faceCount] greaterThenInt: 2];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression pageCount]] lessThenInt: 300];\n    condition = [[condition orString: @\"!myTag1!\"] insideExpression:[CLDConditionExpression tags]];\n    condition = [[condition andString: @\"!myTag2!\"] notInsideExpression:[CLDConditionExpression tags]];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression width]] greaterOrEqualToInt: 200];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression height]] equalToString: @\"$foo\"];\n    condition = [[[[condition and] valueFromExpression:[CLDConditionExpression width]] notEqualToString: @\"$foo\"] multipleByInt: 2];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression height]] lessThenString: @\"$foo\"];\n    condition = [[[condition or] valueFromExpression:[CLDConditionExpression width]] lessOrEqualToInt: 500];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression illustrationScore]] lessThenInt: 0];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression currentPageIndex]] equalToInt: 10];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression pageXOffset]] lessThenInt: 300];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression pageYOffset]] lessThenInt: 300];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression pageYOffset]] notEqualToInt: 400];\n    \n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression aspectRatio]] greaterThenString: @\"3:4\"];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression initialAspectRatio]] greaterThenString: @\"3:4\"];\n    \n    // condition in condition\n    CLDConditionExpression* innerConditionInitialWidth = [[[CLDConditionExpression initialWidth] divideByInt: 2] addByInt: 1];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression height]] lessThenExpression:innerConditionInitialWidth];\n    \n    CLDConditionExpression* innerConditionInitialHeight = [[CLDConditionExpression initialHeight] subtractByString: @\"$foo\"];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression width]] lessThenExpression:innerConditionInitialHeight];\n    \n    // duration\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression duration]] equalToString: @\"$foo\"];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression duration]] notEqualToString: @\"$foo\"];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression duration]] lessThenInt: 30];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression duration]] lessOrEqualToString: @\"$foo\"];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression duration]] greaterThenInt: 30];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression duration]] greaterOrEqualToString: @\"$foo\"];\n    \n    // initial duration\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression initialDuration]] equalToString: @\"$foo\"];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression initialDuration]] notEqualToString: @\"$foo\"];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression initialDuration]] lessThenInt: 30];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression initialDuration]] lessOrEqualToString: @\"$foo\"];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression initialDuration]] greaterThenInt: 30];\n    condition = [[[condition and] valueFromExpression:[CLDConditionExpression initialDuration]] greaterOrEqualToString: @\"$foo\"];\n\n    return condition;\n}\n\n-(NSString*)getExpectedResultToComplexConditionTest {\n    NSMutableString* expectedResult = [NSMutableString string];\n    [expectedResult appendString:@\"$foo_10,$foostr_!my:str:ing!/if_fc_gt_2_and\"];\n    [expectedResult appendString:@\"_pc_lt_300_or\"];\n    [expectedResult appendString:@\"_!myTag1!_in_tags_and\"];\n    [expectedResult appendString:@\"_!myTag2!_nin_tags_and\"];\n    [expectedResult appendString:@\"_w_gte_200_and\"];\n    [expectedResult appendString:@\"_h_eq_$foo_and\"];\n    [expectedResult appendString:@\"_w_ne_$foo_mul_2_and\"];\n    [expectedResult appendString:@\"_h_lt_$foo_or\"];\n    [expectedResult appendString:@\"_w_lte_500_and\"];\n    [expectedResult appendString:@\"_ils_lt_0_and\"];\n    [expectedResult appendString:@\"_cp_eq_10_and\"];\n    [expectedResult appendString:@\"_px_lt_300_and\"];\n    [expectedResult appendString:@\"_py_lt_300_and\"];\n    [expectedResult appendString:@\"_py_ne_400_and\"];\n    [expectedResult appendString:@\"_ar_gt_3:4_and\"];\n    [expectedResult appendString:@\"_iar_gt_3:4_and\"];\n    [expectedResult appendString:@\"_h_lt_iw_div_2_add_1_and\"];\n    [expectedResult appendString:@\"_w_lt_ih_sub_$foo_and\"];\n    [expectedResult appendString:@\"_du_eq_$foo_and\"];\n    [expectedResult appendString:@\"_du_ne_$foo_and\"];\n    [expectedResult appendString:@\"_du_lt_30_and\"];\n    [expectedResult appendString:@\"_du_lte_$foo_and\"];\n    [expectedResult appendString:@\"_du_gt_30_and\"];\n    [expectedResult appendString:@\"_du_gte_$foo_and\"];\n    [expectedResult appendString:@\"_idu_eq_$foo_and\"];\n    [expectedResult appendString:@\"_idu_ne_$foo_and\"];\n    [expectedResult appendString:@\"_idu_lt_30_and\"];\n    [expectedResult appendString:@\"_idu_lte_$foo_and\"];\n    [expectedResult appendString:@\"_idu_gt_30_and\"];\n    [expectedResult appendString:@\"_idu_gte_$foo\"];\n    [expectedResult appendString:@\"/c_scale,l_$foostr,w_$foo_mul_200_div_fc/if_end\"];\n    return [NSString stringWithString: expectedResult];\n}\n\n// MARK: - customPreFunction\n- (void)test_setCustomPreFunction_emptyWasm_shouldReturnValidString {\n    \n    // Given\n    NSString* input = @\"\";\n    \n    NSString* expectedResult = @\"wasm:\";\n    \n    // When\n    CLDCustomFunction* customFunc = [CLDCustomFunction wasm:input];\n    [self.sut setCustomPreFunction:customFunc];\n    \n    NSString* actualResult = [self.sut customPreFunction];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Calling for inserted param should return its value\");\n}\n- (void)test_setCustomPreFunction_wasm_shouldReturnValidString {\n    \n    // Given\n    NSString* input = @\"func\";\n    \n    NSString* expectedResult = @\"wasm:func\";\n    \n    // When\n    [self.sut setCustomPreFunction:[CLDCustomFunction wasm:input]];\n    \n    NSString* actualResult = [self.sut customPreFunction];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Calling for inserted param should return its value\");\n}\n- (void)test_setCustomPreFunction_emptyRemote_shouldReturnValidString {\n    \n    // Given\n    NSString* input = @\"\";\n    \n    NSString* expectedResult = @\"remote:\";\n    \n    // When\n    [self.sut setCustomPreFunction:[CLDCustomFunction remote:input]];\n    \n    NSString* actualResult = [self.sut customPreFunction];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Calling for inserted param should return its value\");\n}\n- (void)test_setCustomPreFunction_remote_shouldReturnValidString {\n    \n    // Given\n    NSString* input = @\"func\";\n    \n    NSString* expectedResult = @\"remote:ZnVuYw==\";\n    \n    // When\n    [self.sut setCustomPreFunction:[CLDCustomFunction remote:input]];\n    \n    NSString* actualResult = [self.sut customPreFunction];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult, expectedResult, \"Calling for inserted param should return its value\");\n}\n\n// MARK: - custom pre functions\n- (void)test_customPreFunction_wasm_shouldReturnExpectedValue {\n   \n    // Given\n    NSString* input = @\"blur_wasm\";\n    \n    NSString* expectedResult = @\"fn_pre:wasm:blur_wasm\";\n    \n    // When\n    self.sut = [[[CLDTransformation alloc] init] setCustomPreFunction:[CLDCustomFunction wasm:input]];\n    NSString* actualResult = [self.sut asString];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, \"actualResult should be equal to expectedResult\");\n}\n- (void)test_customPreFunction_remote_shouldReturnExpectedValue {\n    \n    // Given\n    NSString* input = @\"https://df34ra4a.execute-api.us-west-2.amazonaws.com/default/cloudinaryFunction\";\n    \n    NSString* expectedResult = @\"fn_pre:remote:aHR0cHM6Ly9kZjM0cmE0YS5leGVjdXRlLWFwaS51cy13ZXN0LTIuYW1hem9uYXdzLmNvbS9kZWZhdWx0L2Nsb3VkaW5hcnlGdW5jdGlvbg==\";\n    \n    // When\n    self.sut = [[[CLDTransformation alloc] init] setCustomPreFunction:[CLDCustomFunction remote:input]];\n    NSString* actualResult = [self.sut asString];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, \"actualResult should be equal to expectedResult\");\n}\n\n// MARK: - custom functions\n- (void)test_customFunction_wasm_shouldReturnExpectedValue {\n   \n    // Given\n    NSString* input = @\"blur_wasm\";\n    \n    NSString* expectedResult = @\"fn_wasm:blur_wasm\";\n    \n    // When\n    self.sut = [[[CLDTransformation alloc] init] setCustomFunction:[CLDCustomFunction wasm:input]];\n    NSString* actualResult = [self.sut asString];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, \"actualResult should be equal to expectedResult\");\n}\n- (void)test_customFunction_remote_shouldReturnExpectedValue {\n    \n    // Given\n    NSString* input = @\"https://df34ra4a.execute-api.us-west-2.amazonaws.com/default/cloudinaryFunction\";\n    \n    NSString* expectedResult = @\"fn_remote:aHR0cHM6Ly9kZjM0cmE0YS5leGVjdXRlLWFwaS51cy13ZXN0LTIuYW1hem9uYXdzLmNvbS9kZWZhdWx0L2Nsb3VkaW5hcnlGdW5jdGlvbg==\";\n    \n    // When\n    self.sut = [[[CLDTransformation alloc] init] setCustomFunction:[CLDCustomFunction remote:input]];\n    NSString* actualResult = [self.sut asString];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, \"actualResult should be equal to expectedResult\");\n}\n\n// MARK: - custom functions combinations\n- (void)test_customFunctionCombinations_setPreFirstAndWasm_shouldReturnExpectedValue {\n   \n    // Given\n    NSString* inputPre = @\"preFunc\";\n    NSString* input    = @\"func\";\n    \n    NSString* expectedResult = @\"fn_wasm:func\";\n    \n    // When\n    self.sut = [[[[CLDTransformation alloc] init] setCustomPreFunction:[CLDCustomFunction wasm:inputPre]] setCustomFunction:[CLDCustomFunction wasm:input]];\n    NSString* actualResult = [self.sut asString];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, \"custom pre function should only be used when custom function is not set\");\n}\n- (void)test_customFunctionCombinations_setPreLastAndRemote_shouldReturnExpectedValue {\n   \n    // Given\n    NSString* inputPre = @\"preFunc\";\n    NSString* input    = @\"func\";\n    \n    NSString* expectedResult = @\"fn_pre:remote:cHJlRnVuYw==\";\n    \n    // When\n    self.sut = [[[[CLDTransformation alloc] init] setCustomFunction:[CLDCustomFunction remote:input]] setCustomPreFunction:[CLDCustomFunction remote:inputPre]];\n    NSString* actualResult = [self.sut asString];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, \"custom pre function should only be used when custom function is not set\");\n}\n- (void)test_customFunctionCombinations_setBothWasmAndMultiParams_shouldReturnExpectedValue {\n   \n    // Given\n    NSString* inputPre = @\"preFunc\";\n    NSString* input    = @\"func\";\n    \n    NSString* expectedResult = @\"fn_pre:wasm:preFunc,r_50,w_20,x_40\";\n    \n    // When\n    self.sut = [[[[[[[CLDTransformation alloc] init] setWidthWithInt:20] setCustomFunction:[CLDCustomFunction wasm:input]] setXFromInt:40] setCustomPreFunction:[CLDCustomFunction wasm:inputPre]] setRadiusFromInt:50];\n    NSString* actualResult = [self.sut asString];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, \"custom pre function should only be used when custom function is not set\");\n}\n- (void)test_customFunctionCombinations_setBothRemoteAndMultiParams_shouldReturnExpectedValue {\n   \n    // Given\n    NSString* inputPre = @\"preFunc\";\n    NSString* input    = @\"func\";\n    \n    NSString* expectedResult = @\"fn_pre:remote:cHJlRnVuYw==,r_50,w_20,x_40\";\n    \n    // When\n    self.sut = [[[[[[[CLDTransformation alloc] init] setWidthWithInt:20] setCustomFunction:[CLDCustomFunction remote:input]] setXFromInt:40] setCustomPreFunction:[CLDCustomFunction remote:inputPre]] setRadiusFromInt:50];\n    NSString* actualResult = [self.sut asString];\n    \n    // Then\n    XCTAssertEqualObjects(actualResult ,expectedResult, \"custom pre function should only be used when custom function is not set\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDTransformationTests/CLDTransformationTests.swift",
    "content": "//\n//  CLDTransformationTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass CLDTransformationTests: BaseTestCase {\n     \n    var sut : CLDTransformation!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = CLDTransformation()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - width\n    func test_setWidth_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 200\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setWidth(input)\n        \n        let actualResult = sut.width!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setWidth_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setWidth(input)\n        \n        let actualResult = sut.width!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setWidth_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"200\"\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setWidth(input)\n        \n        let actualResult = sut.width!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setWidth_expression_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDExpression.width().add(by: 200)\n        \n        let expectedResult = \"w_add_200\"\n        \n        // When\n        sut.setWidth(input)\n        \n        let actualResult = sut.width!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - height\n    func test_setHeight_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 200\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setHeight(input)\n        \n        let actualResult = sut.height!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setHeight_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setHeight(input)\n        \n        let actualResult = sut.height!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setHeight_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"height 200\"\n        \n        let expectedResult = \"h_200\"\n        \n        // When\n        sut.setHeight(input)\n        \n        let actualResult = sut.height!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setHeight_expression_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDExpression.height().add(by: 200)\n        let expectedResult = \"h_add_200\"\n        \n        // When\n        sut.setHeight(input)\n        \n        let actualResult = sut.height!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - named\n    func test_setNamed_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"name1\"\n        \n        let expectedResult = \"name1\"\n        \n        // When\n        sut.setNamed(input)\n        \n        let actualResult = sut.named!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setNamed_array_shouldReturnValidString() {\n        \n        // Given\n        let input1 = \"name1\"\n        let input2 = \"name2\"\n        \n        let expectedResult = \"name1.name2\"\n        \n        // When\n        sut.setNamed([input1, input2])\n        \n        let actualResult = sut.named!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - crop\n    func test_setCrop_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"fill\"\n        \n        let expectedResult = \"fill\"\n        \n        // When\n        sut.setCrop(input)\n        \n        let actualResult = sut.crop!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setCrop_CLDCrop_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDTransformation.CLDCrop.fill\n        \n        let expectedResult = \"fill\"\n        \n        // When\n        sut.setCrop(input)\n        \n        let actualResult = sut.crop!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - background\n    func test_setBackground_stringValue_shouldReturnValidString() {\n        \n        // Given\n        let input = \"#rrraaa\"\n        \n        let expectedResult = \"rgb:rrraaa\"\n        \n        // When\n        sut.setBackground(input)\n        \n        let actualResult = sut.background!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - color\n    func test_setColor_stringValue_shouldReturnValidString() {\n        \n        // Given\n        let input = \"#rrraaa\"\n        \n        let expectedResult = \"rgb:rrraaa\"\n        \n        // When\n        sut.setColor(input)\n        \n        let actualResult = sut.color!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - effect\n    func test_setEffect_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"gamma\"\n        \n        let expectedResult = \"gamma\"\n        \n        // When\n        sut.setEffect(input)\n        \n        let actualResult = sut.effect!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setEffect_CLDEffect_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDTransformation.CLDEffect.oilPaint\n        \n        let expectedResult = \"oil_paint\"\n        \n        // When\n        sut.setEffect(input)\n        \n        let actualResult = sut.effect!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setEffect_CLDArt_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDTransformation.CLDArtFilters.alDente\n        \n        let expectedResult = \"art:al_dente\"\n        \n        // When\n        sut.setEffect(input)\n        \n        let actualResult = sut.effect!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setEffect_CLDEffectWithParam_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDTransformation.CLDEffect.gamma\n        let param  = \"200\"\n        \n        let expectedResult = \"gamma:200\"\n        \n        // When\n        sut.setEffect(input, param: param)\n        \n        let actualResult = sut.effect!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setEffect_stringEffectWithParam_shouldReturnValidString() {\n        \n        // Given\n        let input = \"gamma\"\n        let param = \"200\"\n        \n        let expectedResult = \"gamma:200\"\n        \n        // When\n        sut.setEffect(input, param: param)\n        \n        let actualResult = sut.effect!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - angle\n    func test_setAngle_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 200\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setAngle(input)\n        \n        let actualResult = sut.angle!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setAngle_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"200\"\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setAngle(input)\n        \n        let actualResult = sut.angle!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setAngle_array_shouldReturnValidString() {\n        \n        // Given\n        let input = [\"200\", \"300\"]\n        \n        let expectedResult = \"200.300\"\n        \n        // When\n        sut.setAngle(input)\n        \n        let actualResult = sut.angle!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - opacity\n    func test_setOpacity_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 200\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setOpacity(input)\n        \n        let actualResult = sut.opacity!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setOpacity_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"200\"\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setOpacity(input)\n        \n        let actualResult = sut.opacity!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - border\n    func test_setBorder_widthAndColor_shouldReturnValidString() {\n        \n        // Given\n        let input          = 200\n        let color          = \"rgb:222.111.333\"\n        let expectedResult = \"200px_solid_rgb:222.111.333\"\n        \n        // When\n        sut.setBorder(input, color: color)\n        \n        let actualResult = sut.border!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setBorder_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"5px_solid_#111111\"\n        \n        let expectedResult = \"5px_solid_rgb:111111\"\n        \n        // When\n        sut.setBorder(input)\n        \n        let actualResult = sut.border!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - x\n    func test_setX_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 200\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setX(input)\n        \n        let actualResult = sut.x!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setX_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setX(input)\n        \n        let actualResult = sut.x!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setX_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"+ 200\"\n        \n        let expectedResult = \"+_200\"\n        \n        // When\n        sut.setX(input)\n        \n        let actualResult = sut.x!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setX_expression_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDExpression.pageXOffset().add(by: 200)\n        \n        let expectedResult = \"px_add_200\"\n        \n        // When\n        sut.setX(input)\n        \n        let actualResult = sut.x!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - y\n    func test_setY_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 200\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setY(input)\n        \n        let actualResult = sut.y!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setY_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setY(input)\n        \n        let actualResult = sut.y!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setY_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"+ 200\"\n        \n        let expectedResult = \"+_200\"\n        \n        // When\n        sut.setY(input)\n        \n        let actualResult = sut.y!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setY_expression_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDExpression.pageYOffset().add(by: 200)\n        \n        let expectedResult = \"py_add_200\"\n        \n        // When\n        sut.setY(input)\n        \n        let actualResult = sut.y!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - radius\n    func test_setRadius_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 200\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setRadius(input)\n        \n        let actualResult = sut.radius!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setRadius_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"+ 200\"\n        \n        let expectedResult = \"+_200\"\n        \n        // When\n        sut.setRadius(input)\n        \n        let actualResult = sut.radius!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - quality\n    func test_setQuality_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 200\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setQuality(.fixed(input))\n        \n        let actualResult = sut.quality!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setQuality_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"200\"\n        \n        let expectedResult = \"200\"\n        \n        // When\n        sut.setQuality(input)\n        \n        let actualResult = sut.quality!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setQuality_CLDQuality_shouldReturnValidString() { \n        \n        // Given\n        let input = CLDTransformation.CLDQuality.auto()\n        \n        let expectedResult = \"auto\"\n        \n        // When\n        sut.setQuality(input)\n        \n        let actualResult = sut.quality!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setQuality_CLDQualityBest_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDTransformation.CLDQuality.auto(.best)\n        \n        let expectedResult = \"auto:best\"\n        \n        // When\n        sut.setQuality(input)\n        \n        let actualResult = sut.quality!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setQuality_CLDQualityGood_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDTransformation.CLDQuality.auto(.good)\n        \n        let expectedResult = \"auto:good\"\n        \n        // When\n        sut.setQuality(input)\n        \n        let actualResult = sut.quality!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setQuality_CLDQualityEco_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDTransformation.CLDQuality.auto(.eco)\n        \n        let expectedResult = \"auto:eco\"\n        \n        // When\n        sut.setQuality(input)\n        \n        let actualResult = sut.quality!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setQuality_CLDQualityLow_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDTransformation.CLDQuality.auto(.low)\n        \n        let expectedResult = \"auto:low\"\n        \n        // When\n        sut.setQuality(input)\n        \n        let actualResult = sut.quality!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n\n    // MARK: - defaultImage\n    func test_setDefaultImage_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"image1\"\n        \n        let expectedResult = \"image1\"\n        \n        // When\n        sut.setDefaultImage(input)\n        \n        let actualResult = sut.defaultImage!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - gravity\n    func test_setGravity_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"right\"\n        \n        let expectedResult = \"right\"\n        \n        // When\n        sut.setGravity(input)\n        \n        let actualResult = sut.gravity!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setGravity_CLDGravity_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDTransformation.CLDGravity.center\n        \n        let expectedResult = \"center\"\n        \n        // When\n        sut.setGravity(input)\n        \n        let actualResult = sut.gravity!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - colorSpace\n    func test_setColorSpace_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"blue\"\n        \n        let expectedResult = \"blue\"\n        \n        // When\n        sut.setColorSpace(input)\n        \n        let actualResult = sut.colorSpace!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - prefix\n    func test_setPrefix_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"www\"\n        \n        let expectedResult = \"www\"\n        \n        // When\n        sut.setPrefix(input)\n        \n        let actualResult = sut.prefix!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - overlay\n    func test_setOverlay_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"image\"\n        \n        let expectedResult = \"image\"\n        \n        // When\n        sut.setOverlay(input)\n        \n        let actualResult = sut.overlay!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - underlay\n    func test_setUnderlay_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"image\"\n        \n        let expectedResult = \"image\"\n        \n        // When\n        sut.setUnderlay(input)\n        \n        let actualResult = sut.underlay!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - fetschFormat\n    func test_setFetchFormat_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"format\"\n        \n        let expectedResult = \"format\"\n        \n        // When\n        sut.setFetchFormat(input)\n        \n        let actualResult = sut.fetchFormat!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - density\n    func test_setDensity_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 30\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setDensity(input)\n        \n        let actualResult = sut.density!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setDensity_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setDensity(input)\n        \n        let actualResult = sut.density!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - page\n    func test_setPage_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 30\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setPage(input)\n        \n        let actualResult = sut.page!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setPage_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setPage(input)\n        \n        let actualResult = sut.page!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - delay\n    func test_setDelay_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 30\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setDelay(input)\n        \n        let actualResult = sut.delay!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setDelay_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setDelay(input)\n        \n        let actualResult = sut.delay!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - rawTransformation\n    func test_setRawTransformation_shouldReturnValidString() {\n        \n        // Given\n        let input = \"r_w_add_200\"\n        \n        let expectedResult = \"r_w_add_200\"\n        \n        // When\n        sut.setRawTransformation(input)\n        \n        let actualResult = sut.rawTransformation!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setRawTransformation_multiProperties_shouldOrderTransformation() {\n        \n        // Given\n        let input = \"r_w_add_200\"\n        \n        let expectedResult = \"c_fit,w_100,r_w_add_200\"\n        \n        // When\n        sut.setCrop(.fit).setRawTransformation(input).setWidth(100)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setRawTransformation_ifEnd_shouldOrderTransformation() {\n        \n        // Given\n        let input = \"r_w_add_200\"\n        \n        let expectedResult = \"if_w_gt_100/c_fit,w_100,r_w_add_200/if_end\"\n        \n        // When\n        sut.ifCondition().width(\">\", 100).then().setCrop(.fit).setRawTransformation(input).setWidth(100).endIf()\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - flags\n    func test_setFlags_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30.20.10\"\n        \n        let expectedResult = \"30.20.10\"\n        \n        // When\n        sut.setFlags(input)\n        \n        let actualResult = sut.flags!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setFlags_array_shouldReturnValidString() {\n        \n        // Given\n        let input = [\"30\",\"20\",\"10\"]\n        \n        let expectedResult = \"30.20.10\"\n        \n        // When\n        sut.setFlags(input)\n        \n        let actualResult = sut.flags!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - dpr\n    func test_setDpr_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setDpr(input)\n        \n        let actualResult = sut.dpr!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setDpr_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setDpr(input)\n        \n        let actualResult = sut.dpr!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - zoom\n    func test_setZoom_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setZoom(input)\n        \n        let actualResult = sut.zoom!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setZoom_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setZoom(input)\n        \n        let actualResult = sut.zoom!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - aspectRatio\n    func test_setAspectRatio_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setAspectRatio(input)\n        \n        let actualResult = sut.aspectRatio!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setAspectRatio_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"3:4\"\n        \n        let expectedResult = \"3:4\"\n        \n        // When\n        sut.setAspectRatio(input)\n        \n        let actualResult = sut.aspectRatio!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setAspectRatio_int_shouldReturnValidString() {\n        \n        // Given\n        let inputNominator   = 3\n        let inputDenuminator = 4\n        \n        let expectedResult = \"3:4\"\n        \n        // When\n        sut.setAspectRatio(nominator: inputNominator, denominator: inputDenuminator)\n        \n        let actualResult = sut.aspectRatio!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - custom pre functions\n    func test_customPreFunction_wasm_shouldReturnExpectedValue(){\n       \n        // Given\n        let input = \"blur_wasm\"\n        \n        let expectedResult = \"fn_pre:wasm:blur_wasm\"\n        \n        // When\n        let sut = CLDTransformation().setCustomPreFunction(.wasm(input))\n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult ,expectedResult, \"actualResult should be equal to expectedResult\")\n    }\n    func test_customPreFunction_remote_shouldReturnExpectedValue(){\n        \n        // Given\n        let input = \"https://df34ra4a.execute-api.us-west-2.amazonaws.com/default/cloudinaryFunction\"\n        \n        let expectedResult = \"fn_pre:remote:aHR0cHM6Ly9kZjM0cmE0YS5leGVjdXRlLWFwaS51cy13ZXN0LTIuYW1hem9uYXdzLmNvbS9kZWZhdWx0L2Nsb3VkaW5hcnlGdW5jdGlvbg==\"\n        \n        // When\n        let sut = CLDTransformation().setCustomPreFunction(.remote(input))\n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult ,expectedResult, \"actualResult should be equal to expectedResult\")\n    }\n    \n    func test_setCustomPreFunction_emptyWasm_shouldReturnValidString() {\n        \n        // Given\n        let input = \"\"\n        \n        let expectedResult = \"wasm:\"\n        \n        // When\n        sut.setCustomPreFunction(.wasm(input))\n        \n        let actualResult = sut.customPreFunction!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setCustomPreFunction_wasm_shouldReturnValidString() {\n        \n        // Given\n        let input = \"func\"\n        \n        let expectedResult = \"wasm:func\"\n        \n        // When\n        sut.setCustomPreFunction(.wasm(input))\n        \n        let actualResult = sut.customPreFunction!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setCustomPreFunction_emptyRemote_shouldReturnValidString() {\n        \n        // Given\n        let input = \"\"\n        \n        let expectedResult = \"remote:\"\n        \n        // When\n        sut.setCustomPreFunction(.remote(input))\n        \n        let actualResult = sut.customPreFunction!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setCustomPreFunction_remote_shouldReturnValidString() {\n        \n        // Given\n        let input = \"func\"\n        \n        let expectedResult = \"remote:ZnVuYw==\"\n        \n        // When\n        sut.setCustomPreFunction(.remote(input))\n        \n        let actualResult = sut.customPreFunction!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - custom functions\n    func test_customFunction_wasm_shouldReturnExpectedValue(){\n       \n        // Given\n        let input = \"blur_wasm\"\n        \n        let expectedResult = \"fn_wasm:blur_wasm\"\n        \n        // When\n        let sut = CLDTransformation().setCustomFunction(.wasm(input))\n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult ,expectedResult, \"actualResult should be equal to expectedResult\")\n    }\n    func test_customFunction_remote_shouldReturnExpectedValue(){\n        \n        // Given\n        let input = \"https://df34ra4a.execute-api.us-west-2.amazonaws.com/default/cloudinaryFunction\"\n        \n        let expectedResult = \"fn_remote:aHR0cHM6Ly9kZjM0cmE0YS5leGVjdXRlLWFwaS51cy13ZXN0LTIuYW1hem9uYXdzLmNvbS9kZWZhdWx0L2Nsb3VkaW5hcnlGdW5jdGlvbg==\"\n        \n        // When\n        let sut = CLDTransformation().setCustomFunction(.remote(input))\n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult ,expectedResult, \"actualResult should be equal to expectedResult\")\n    }\n    func test_setCustomFunction_wasm_shouldReturnValidString() {\n        \n        // Given\n        let input = \"func\"\n        \n        let expectedResult = \"wasm:func\"\n        \n        // When\n        sut.setCustomFunction(.wasm(input))\n        \n        let actualResult = sut.customFunction!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setCustomFunction_remote_shouldReturnValidString() {\n        \n        // Given\n        let input = \"func\"\n        \n        let expectedResult = \"remote:ZnVuYw==\"\n        \n        // When\n        sut.setCustomFunction(.remote(input))\n        \n        let actualResult = sut.customFunction!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - custom functions combinations\n    func test_customFunctionCombinations_setPreFirstAndWasm_shouldReturnExpectedValue(){\n       \n        // Given\n        let inputPre = \"preFunc\"\n        let input    = \"func\"\n        \n        let expectedResult = \"fn_wasm:func\"\n    \n        // When\n        let sut = CLDTransformation().setCustomPreFunction(.wasm(inputPre)).setCustomFunction(.wasm(input))\n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult ,expectedResult, \"custom pre function should only be used when custom function is not set\")\n    }\n    func test_customFunctionCombinations_setPreLastAndRemote_shouldReturnExpectedValue(){\n       \n        // Given\n        let inputPre = \"preFunc\"\n        let input    = \"func\"\n        \n        let expectedResult = \"fn_pre:remote:cHJlRnVuYw==\"\n        \n        // When\n        let sut = CLDTransformation().setCustomFunction(.remote(input)).setCustomPreFunction(.remote(inputPre))\n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult ,expectedResult, \"custom pre function should only be used when custom function is not set\")\n    }\n    func test_customFunctionCombinations_setBothWasmAndMultiParams_shouldReturnExpectedValue(){\n       \n        // Given\n        let inputPre = \"preFunc\"\n        let input    = \"func\"\n        \n        let expectedResult = \"dpr_20.0,fn_pre:wasm:preFunc,r_10,w_40,x_30\"\n        \n        // When\n        let sut = CLDTransformation().setWidth(40).setCustomFunction(.wasm(input)).setX(30).setCustomPreFunction(.wasm(inputPre)).setDpr(20.0).setRadius(10)\n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult ,expectedResult, \"custom pre function should only be used when custom function is not set\")\n    }\n    func test_customFunctionCombinations_setBothRemoteAndMultiParams_shouldReturnExpectedValue(){\n       \n        // Given\n        let inputPre = \"preFunc\"\n        let input    = \"func\"\n        \n        let expectedResult = \"dpr_20.0,fn_pre:remote:cHJlRnVuYw==,r_10,w_40,x_30\"\n        \n        // When\n        let sut = CLDTransformation().setWidth(40).setCustomFunction(.remote(input)).setX(30).setCustomPreFunction(.remote(inputPre)).setDpr(20.0).setRadius(10)\n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult ,expectedResult, \"custom pre function should only be used when custom function is not set\")\n    }\n    \n    // MARK: - audioCodec\n    func test_setAudioCodec_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"sound\"\n        \n        let expectedResult = \"sound\"\n        \n        // When\n        sut.setAudioCodec(input)\n        \n        let actualResult = sut.audioCodec!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - audioFrequency\n    func test_setAudioFrequency_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 30\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setAudioFrequency(input)\n        \n        let actualResult = sut.audioFrequency!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setAudioFrequency_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setAudioFrequency(input)\n        \n        let actualResult = sut.audioFrequency!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - bitRate\n    func test_setBitRate_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 30\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setBitRate(input)\n        \n        let actualResult = sut.bitRate!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setBitRate_intK_shouldReturnValidString() {\n        \n        // Given\n        let input = 30\n        \n        let expectedResult = \"30k\"\n        \n        // When\n        sut.setBitRate(kb: input)\n        \n        let actualResult = sut.bitRate!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setBitRate_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setBitRate(input)\n        \n        let actualResult = sut.bitRate!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - videoSampling\n    func test_setVideoSampling_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 30\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setVideoSampling(frames:input)\n        \n        let actualResult = sut.videoSampling!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setVideoSampling_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3s\"\n        \n        // When\n        sut.setVideoSampling(delay: input)\n        \n        let actualResult = sut.videoSampling!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setVideoSampling_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setVideoSampling(input)\n        \n        let actualResult = sut.videoSampling!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - duration\n    func test_setDuration_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 30\n        \n        let expectedResult = \"30p\"\n        \n        // When\n        sut.setDuration(percent: input)\n        \n        let actualResult = sut.duration!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setDuration_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setDuration(seconds: input)\n        \n        let actualResult = sut.duration!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setDuration_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setDuration(input)\n        \n        let actualResult = sut.duration!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - startOffset\n    func test_setStartOffset_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 30\n        \n        let expectedResult = \"30p\"\n        \n        // When\n        sut.setStartOffset(percent: input)\n        \n        let actualResult = sut.startOffset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setStartOffset_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setStartOffset(seconds: input)\n        \n        let actualResult = sut.startOffset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setStartOffset_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setStartOffset(input)\n        \n        let actualResult = sut.startOffset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - endOffset\n    func test_setEndOffset_int_shouldReturnValidString() {\n        \n        // Given\n        let input = 30\n        \n        let expectedResult = \"30p\"\n        \n        // When\n        sut.setEndOffset(percent: input)\n        \n        let actualResult = sut.endOffset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setEndOffset_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setEndOffset(seconds: input)\n        \n        let actualResult = sut.endOffset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setEndOffset_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setEndOffset(input)\n        \n        let actualResult = sut.endOffset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - startOffsetAndEndOffset\n    func test_setStartOffsetAndEndOffset_shouldReturnValidString() {\n        \n        // Given\n        let inputStart = Float(30.3)\n        let inputEnd   = Float(20.2)\n        \n        let expectedResult = \"eo_20.2,so_30.3\"\n        \n        // When\n        sut.setStartOffsetAndEndOffset(startSeconds: inputStart, endSeconds: inputEnd)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setStartOffsetAndEndOffset_percent_shouldReturnValidString() {\n        \n        // Given\n        let inputStart = 20\n        let inputEnd   = 30\n        \n        let expectedResult = \"eo_30p,so_20p\"\n        \n        // When\n        sut.setStartOffsetAndEndOffset(startPercent: inputStart, endPercent: inputEnd)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - videoCodec\n    func test_setVideoCodec_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setVideoCodec(input)\n        \n        let actualResult = sut.videoCodec!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - param\n    func test_setParam_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        let key   = CLDTransformation.TransformationParam.ANGLE.rawValue\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setParam(key, value: input)\n        \n        let actualResult = sut.angle!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - offset\n    func test_setOffset_intArray_shouldReturnValidString() {\n        \n        // Given\n        let input = [30,20]\n        \n        let expectedResult = [\"30p\",\"20p\"]\n        \n        // When\n        sut.setOffset(percents: input)\n        \n        let actualResult = sut.offset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setOffset_oneValueIntArray_shouldReturnValidString() {\n        \n        // Given\n        let input = [30]\n        \n        let expectedResult = [\"30p\",\"30p\"]\n        \n        // When\n        sut.setOffset(percents: input)\n        \n        let actualResult = sut.offset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setOffset_emptyIntArray_shouldNotStoreParam() {\n        \n        // Given\n        let input = [Int]()\n        \n        // When\n        sut.setOffset(percents: input)\n        \n        let actualResult = sut.offset\n        \n        // Then\n        XCTAssertNil(actualResult, \"offset should not be stored without a valid array\")\n    }\n    func test_setOffset_floatArray_shouldReturnValidString() {\n        \n        // Given\n        let input = [Float(30.3),Float(20.2)]\n        \n        let expectedResult = [\"30.3\",\"20.2\"]\n        \n        // When\n        sut.setOffset(seconds: input)\n        \n        let actualResult = sut.offset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setOffset_oneValueFloatArray_shouldReturnValidString() {\n        \n        // Given\n        let input = [Float(30.3)]\n        \n        let expectedResult = [\"30.3\",\"30.3\"]\n        \n        // When\n        sut.setOffset(seconds: input)\n        \n        let actualResult = sut.offset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setOffset_emptyFloatArray_shouldNotStoreParam() {\n        \n        // Given\n        let input = [Float]()\n        \n        // When\n        sut.setOffset(seconds: input)\n        \n        let actualResult = sut.offset\n        \n        // Then\n        XCTAssertNil(actualResult, \"offset should not be stored without a valid array\")\n    }\n    func test_setOffset_stringArray_shouldReturnValidString() {\n        \n        // Given\n        let input = [\"30\",\"20\"]\n        \n        let expectedResult = [\"30\",\"20\"]\n        \n        // When\n        sut.setOffset(input)\n        \n        let actualResult = sut.offset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setOffset_oneValueStringArray_shouldReturnValidString() {\n        \n        // Given\n        let input = [\"30\"]\n        \n        let expectedResult = [\"30\",\"30\"]\n        \n        // When\n        sut.setOffset(input)\n        \n        let actualResult = sut.offset!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setOffset_emptyStringArray_shouldNotStoreParam() {\n        \n        // Given\n        let input = [String]()\n        \n        // When\n        sut.setOffset(input)\n        \n        let actualResult = sut.offset\n        \n        // Then\n        XCTAssertNil(actualResult, \"offset should not be stored without a valid array\")\n    }\n    \n    // MARK: - fps\n    func test_setFps_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setFps(input)\n        \n        let actualResult = sut.fps!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setFps_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setFps(input)\n        \n        let actualResult = sut.fps!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setFps_CLDFps_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDTransformation.CLDFps.fromFloat(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setFps(input)\n        \n        let actualResult = sut.fps!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - overlayWithLayer\n    func test_setOverlayWithLayer_float_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDLayer().setPublicId(publicId: \"logo\")\n        \n        let expectedResult = \"logo\"\n        \n        // When\n        sut.setOverlayWithLayer(input)\n        \n        let actualResult = sut.overlay!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - underlayWithLayer\n    func test_setUnderlayWithLayer_float_shouldReturnValidString() {\n        \n        // Given\n        let input = CLDLayer().setPublicId(publicId: \"logo\")\n        \n        let expectedResult = \"logo\"\n        \n        // When\n        sut.setUnderlayWithLayer(input)\n        \n        let actualResult = sut.underlay!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - topLeftPoint\n    func test_setTopLeftPoint_shouldReturnValidString() {\n        \n        // Given\n        let input = CGPoint(x: 20.2, y: 30.3)\n        \n        let expectedResult = \"x_20.2,y_30.3\"\n        \n        // When\n        sut.setTopLeftPoint(input)\n        \n        let actualResult = sut.asString()!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - keyframeInterval\n    func test_setKeyframeInterval_float_shouldReturnValidString() {\n        \n        // Given\n        let input = Float(30.3)\n        \n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setKeyframeInterval(interval: input)\n        \n        let actualResult = sut.keyframeInterval!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    func test_setKeyframeInterval_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setKeyframeInterval(input)\n        \n        let actualResult = sut.keyframeInterval!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n    \n    // MARK: - keyframeInterval\n    func test_setStreamingProfile_string_shouldReturnValidString() {\n        \n        // Given\n        let input = \"30\"\n        \n        let expectedResult = \"30\"\n        \n        // When\n        sut.setStreamingProfile(input)\n        \n        let actualResult = sut.streamingProfile!\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling for inserted param should return its value\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDTransformationTests/CLDTransformationVariablesTests.swift",
    "content": "//\n//  CLDTransformationVariablesTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass CLDTransformationVariablesTests: BaseTestCase {\n     \n    var sut : CLDTransformation!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n        sut = CLDTransformation()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - test invalid variable using get param\n    func test_setVariable_emptyInputParamaters_shouldNotStoreNewVariable() {\n        \n        // Given\n        let variableName  = String()\n        let variableValue = String()\n        \n        // When\n        sut.setVariable(variableName, string: variableValue)\n        \n        let actualResult = sut.getParam(variableName)\n        \n        // Then\n        XCTAssertNil(actualResult, \"Empty CLDVariable should not be stored in params\")\n    }\n    func test_setVariable_emptyValueParamater_shouldNotStoreNewVariable() {\n        \n        // Given\n        let variableName  = \"$foo\"\n        let variableValue = String()\n        \n        // When\n        sut.setVariable(variableName, string: variableValue)\n        \n        let actualResult = sut.getParam(variableName)\n        \n        // Then\n        XCTAssertNil(actualResult, \"Empty CLDVariable should not be stored in params\")\n    }\n    \n    // MARK: - test set variable using get param\n    func test_setVariable_validParamaters_shouldStoreNewVariable() {\n        \n        // Given\n        let variableName   = \"$foo\"\n        let variableValue  = Float(30.3)\n        let expectedResult = \"30.3\"\n        \n        // When\n        sut.setVariable(variableName, float: variableValue)\n        \n        let actualResult = sut.getParam(variableName)\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling getParam on an CLDTransformation with a valid CLDVariable name as param, should return its value\")\n    }\n    func test_setVariable_stringParamaters_shouldStoreNewVariable() {\n        \n        // Given\n        let variableName   = \"$foo\"\n        let variableValue  = \"bar\"\n        let expectedResult = \"bar\"\n        \n        // When\n        sut.setVariable(variableName, string: variableValue)\n        \n        let actualResult = sut.getParam(variableName)\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling getParam on an CLDTransformation with a valid CLDVariable name as param, should return its value\")\n    }\n    func test_setVariable_validVariableObject_shouldStoreNewVariable() {\n        \n        // Given\n        let variableName   = \"$foo\"\n        let variableValue  = \"bar\"\n        let variable       = CLDVariable(name: variableName, value: variableValue)\n        let expectedResult = \"bar\"\n        \n        // When\n        sut.setVariable(variable)\n        \n        let actualResult = sut.getParam(variableName)\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling getParam on an CLDTransformation with a valid CLDVariable name as param, should return its value\")\n    }\n    func test_setVariable_twoValidVariableObjectsOneLine_shouldStoreNewVariable() {\n        \n        // Given\n        let variableName1   = \"$foo\"\n        let variableValue1  = \"bar\"\n        let variableName2   = \"$nurf\"\n        let variableValue2  = \"baz\"\n        let variable1       = CLDVariable(name: variableName1, value: variableValue1)\n        let variable2       = CLDVariable(name: variableName2, value: variableValue2)\n        let expectedResult1 = \"bar\"\n        let expectedResult2 = \"baz\"\n        \n        \n        // When\n        sut.setVariable(variable1).setVariable(variable2)\n        \n        let actualResult1 = sut.getParam(variableName1)\n        let actualResult2 = sut.getParam(variableName2)\n        \n        // Then\n        XCTAssertEqual(actualResult1, expectedResult1, \"Calling getParam on an CLDTransformation with a valid CLDVariable name as param, should return its value\")\n        XCTAssertEqual(actualResult2, expectedResult2, \"Calling getParam on an CLDTransformation with a valid CLDVariable name as param, should return its value\")\n    }\n    func test_setVariables_validVariablesArray_shouldStoreNewVariable() {\n        \n        // Given\n        let variableName   = \"$foo\"\n        let variableValue  = \"bar\"\n        let variable       = CLDVariable(name: variableName, value: variableValue)\n        let expectedResult = \"$foo_bar\"\n        \n        // When\n        sut.setVariables([variable])\n        \n        let actualResult = sut.variables\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling sut.variables should return its value\")\n    }\n    func test_setVariables_twoValidVariablesArray_shouldStoreNewVariable() {\n        \n        // Given\n        let variableName    = \"$foo\"\n        let variableValue   = \"bar\"\n        let variableName2   = \"$nurf\"\n        let variableValue2  = \"baz\"\n        let variable        = CLDVariable(name: variableName , value: variableValue)\n        let variable2       = CLDVariable(name: variableName2, value: variableValue2)\n        let expectedResult  = \"$foo_bar,$nurf_baz\"\n        \n        // When\n        sut.setVariables([variable, variable2])\n        \n        let actualResult  = sut.variables\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling sut.variables should return its value\")\n    }\n    \n    // MARK: - test asString() on empty variable\n    func test_asString_variableWithEmptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let variableName   = String()\n        let variableValue  = String()\n        let expectedResult = String()\n        \n        // When\n        sut.setVariable(variableName, string: variableValue)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Empty CLDVariable should not be stored in params\")\n    }\n    func test_asString_variablesArrayWithEmptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let variable = CLDVariable()\n        let expectedResult: String? = nil\n        \n        // When\n        sut.setVariables([variable])\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Empty CLDVariable should not be stored in params\")\n    }\n    \n    // MARK: - test asString() on variable\n    func test_asString_validVariable_shouldReturnValidString() {\n        \n        // Given\n        let variableName   = \"foo\"\n        let variableValue  = \"bar\"\n        let expectedResult = \"$foo_bar\"\n        \n        // When\n        sut.setVariable(variableName, string: variableValue)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString() on an CLDTransformation with a valid CLDVariable as param, should return the expected string\")\n    }\n    \n    func test_asString_validOneVariableArray_shouldReturnValidString() {\n        \n        // Given\n        let variableName   = \"foo\"\n        let variableValue  = \"bar\"\n        let variable = CLDVariable(name: variableName, value: variableValue)\n        let expectedResult = \"$foo_bar\"\n        \n        // When\n        sut.setVariables([variable])\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString() on an CLDTransformation with a valid CLDVariable as param, should return the expected string\")\n    }\n    \n    func test_asString_validTwoVariablesArray_shouldReturnValidString() {\n        \n        // Given\n        let variableName   = \"foo\"\n        let variableValue  = \"bar\"\n        let variableName2  = \"foo2\"\n        let variableValue2 = \"bar2\"\n        let variable       = CLDVariable(name: variableName, value: variableValue)\n        let variable2      = CLDVariable(name: variableName2, value: variableValue2)\n        let expectedResult = \"$foo_bar,$foo2_bar2\"\n        \n        // When\n        sut.setVariables([variable, variable2])\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString() on an CLDTransformation with a valid CLDVariable as param, should return the expected string\")\n    }\n    \n    func test_asString_validTwoVariablesArray_shouldReturnValidStringOrderedByEntry() {\n        \n        // Given\n        let variableName   = \"foo\"\n        let variableValue  = \"bar\"\n        let variableName2  = \"nurf\"\n        let variableValue2 = \"baz\"\n        let variable       = CLDVariable(name: variableName, value: variableValue)\n        let variable2      = CLDVariable(name: variableName2, value: variableValue2)\n        let expectedResult = \"$nurf_baz,$foo_bar\"\n        \n        // When\n        sut.setVariables([variable2, variable])\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString() on an CLDTransformation with a valid CLDVariable as param, should return the expected string\")\n    }\n    \n    func test_asString_validTwoVariablesArrayAndParams_shouldReturnValidSortedString() {\n        \n        // Given\n        let variableName   = \"foo\"\n        let variableValue  = \"bar\"\n        let variableName2  = \"foo2\"\n        let variableValue2 = \"bar2\"\n        let variable       = CLDVariable(name: variableName, value: variableValue)\n        let variable2      = CLDVariable(name: variableName2, value: variableValue2)\n        let expectedResult = \"$foo_bar,$foo2_bar2,h_12.0,w_11.0\"\n        \n        // When\n        sut.setWidth(11.0)\n        sut.setVariables([variable, variable2])\n        sut.setHeight(12.0)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString() on an CLDTransformation with a valid CLDVariable as param, should return the expected string - variables first!\")\n    }\n    \n    func test_asString_validTwoVariablesArrayAndParams_shouldReturnValidSortedStringVariablesOrderedByEntry() {\n        \n        // Given\n        let variableName1  = \"foo1\"\n        let variableValue1 = \"bar1\"\n        let variableName2  = \"foo2\"\n        let variableValue2 = \"bar2\"\n        let variableName3  = \"foo3\"\n        let variableValue3 = \"bar3\"\n        let variable1      = CLDVariable(name: variableName1, value: variableValue1)\n        let variable2      = CLDVariable(name: variableName2, value: variableValue2)\n        let variable3      = CLDVariable(name: variableName3, value: variableValue3)\n        let expectedResult = \"$foo3_bar3,$foo1_bar1,$foo2_bar2,h_12.0,w_11.0\"\n        \n        // When\n        sut.setVariable(variable2)\n        sut.setWidth(11.0)\n        sut.setVariables([variable3, variable1])\n        sut.setHeight(12.0)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString() on an CLDTransformation with a valid CLDVariable as param, should return the expected string - variables first!\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDVariableTests/CLDVariableTests.m",
    "content": "//\n//  ObjcCLDVariableTests.m\n//\n//  Copyright (c) 2018 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"ObjcBaseTestCase.h\"\n\n@interface ObjcCLDVariableTests : ObjcBaseTestCase\n\n@end\n\n@implementation ObjcCLDVariableTests\n\nCLDVariable *sut;\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n}\n\n- (void)tearDown {\n    [super tearDown];\n    sut = nil;\n}\n\n// MARK: - test initilization methods - empty\n- (void)test_init_emptyInputParamaters_shouldStoreEmptyProperties {\n        \n    // Given\n    NSString *name = [NSString string];\n    \n    // When\n    sut = [[CLDVariable alloc] init];\n    \n    // Then\n    XCTAssertNotNil(sut.name, \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should contain a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: [NSString string]], \"Initilized object should contain an empty string as value property\");\n    XCTAssertFalse([sut.name isEqualToString: name], \"Name property should contain \\\"\\(CLDVariable.variableNamePrefix)\\\" prefix\");\n}\n\n// MARK: - test initilization methods - value\n-(void)test_init_emptyNameParamater_shouldStoreEmptyNameProperty {\n    \n    // Given\n    NSString *name  = [NSString string];\n    NSString *value = @\"alue\";\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name stringValue:value];\n    \n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should contain a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: value], \"Initilized object should contain an empty string as value property\");\n}\n-(void)test_init_validStringParamatersAndNoNamePrefix_shouldStoreValidProperties {\n    \n    // Given\n    NSString *name  = @\"name\";\n    NSString *value = @\"alue\";\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name stringValue:value];\n\n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should have a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: value], \"Initilized object should contain a string as value property\");\n}\n-(void)test_init_validStringParamaters_shouldStoreValidProperties {\n    \n    // Given\n    NSString *name  = @\"$foo\";\n    NSString *value = @\"alue\";\n   \n    // When\n    sut = [[CLDVariable alloc] initWithName:name stringValue:value];\n\n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: name], \"Initilized object should contain a string as name property\");\n    XCTAssertTrue([sut.value isEqualToString: value], \"Initilized object should contain a string as value property\");\n}\n-(void)test_init_emptyNameParamaterIntValue_shouldStoreEmptyNameProperty {\n    \n    // Given\n    NSString *name  = [NSString string];\n    int value = 4;\n    NSString* valueAsString = [@(value) stringValue];\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name intValue:value];\n    \n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should have a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: valueAsString], \"Initilized object should contain a string as value property\");\n}\n-(void)test_init_validIntValue_shouldStoreValidProperties {\n    \n    // Given\n    NSString *name  = @\"name\";\n    int value = 4;\n    NSString* valueAsString = [@(value) stringValue];\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name intValue:value];\n    \n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should have a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: valueAsString], \"Initilized object should contain a string as value property\");\n}\n-(void)test_init_emptyNameParamaterDoubleValue_shouldStoreEmptyNameProperty {\n    \n    // Given\n    NSString *name  = [NSString string];\n    double value = 3.14;\n    NSString* valueAsString = [@(value) stringValue];\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name doubleValue:value];\n    \n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should have a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: valueAsString], \"Initilized object should contain a string as value property\");\n}\n-(void)test_init_validDoubleValue_shouldStoreValidProperties {\n    \n    // Given\n    NSString *name = @\"name\";\n    double value = 3.14;\n    NSString* valueAsString = [@(value) stringValue];\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name doubleValue:value];\n    \n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should have a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: valueAsString], \"Initilized object should contain a string as value property\");\n}\n\n// MARK: - test initilization methods - values\n-(void)test_initWithValuesArray_emptyInputParamaters_shouldStoreEmptyProperties {\n    \n    // Given\n    NSString *name = [NSString string];\n    NSArray *values = @[];\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name values:values];\n    \n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should have a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: [NSString string]], \"Initilized object should contain a string as value property\");\n}\n-(void)test_initWithValuesArray_emptyValueParamater_shouldStoreEmptyValueProperty {\n    \n    // Given\n    NSString *name = @\"name\";\n    NSArray *values = @[];\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name values:values];\n    \n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should have a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: [NSString string]], \"Initilized object should contain a string as value property\");\n}\n-(void)test_initWithValuesArray_validOneValueArray_shouldStoreValidProperties {\n    \n    // Given\n    NSString *name = @\"name\";\n    NSArray *values = @[@\"my\"];\n    NSString *expectedResult = @\"!my!\";\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name values:values];\n    \n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should have a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: expectedResult], \"Initilized object should contain a string as value property\");\n}\n-(void)test_initWithValuesArray_validTwoValueArray_shouldStoreValidProperties {\n    \n    // Given\n    NSString *name = @\"name\";\n    NSArray *values = @[@\"my\",@\"str\"];\n    NSString *expectedResult = @\"!my:str!\";\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name values:values];\n    \n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should have a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: expectedResult], \"Initilized object should contain a string as value property\");\n}\n-(void)test_initWithValuesArray_validThreeValuesArray_shouldStoreValidProperties {\n    \n    // Given\n    NSString *name = @\"name\";\n    NSArray *values = @[@\"my\",@\"str\",@\"ing\"];\n    NSString *expectedResult = @\"!my:str:ing!\";\n    \n    // When\n    sut = [[CLDVariable alloc] initWithName:name values:values];\n    \n    // Then\n    XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\");\n    XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\");\n    \n    XCTAssertTrue([sut.name isEqualToString: [CLDVariable.variableNamePrefix stringByAppendingString:name]], \"Name property should have a valid prefix\");\n    XCTAssertTrue([sut.value isEqualToString: expectedResult], \"Initilized object should contain a string as value property\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/TransformationTests/CLDVariableTests/CLDVariableTests.swift",
    "content": "//\n//  CLDTransformationTests.swift\n//\n//\n//  Permission is hereby granted, free of charge, to any person obtaining a copy\n//  of this software and associated documentation files (the \"Software\"), to deal\n//  in the Software without restriction, including without limitation the rights\n//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n//  copies of the Software, and to permit persons to whom the Software is\n//  furnished to do so, subject to the following conditions:\n//\n//  The above copyright notice and this permission notice shall be included in\n//  all copies or substantial portions of the Software.\n//\n//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n//  THE SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass CLDVariableTests: BaseTestCase {\n    \n    var sut : CLDVariable!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    \n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - test initilization methods - empty\n    func test_init_emptyInputParamaters_shouldStoreEmptyProperties() {\n        \n        // Given\n        let name = String()\n        \n        // When\n        sut = CLDVariable()\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should contain a valid prefix\")\n        XCTAssertEqual(sut.value, String(), \"Initilized object should contain an empty string as value property\")\n        XCTAssertNotEqual(sut.name , name, \"Name property should contain \\\"\\(CLDVariable.variableNamePrefix)\\\" prefix\")\n    }\n    \n    // MARK: - test initilization methods - value\n    func test_init_emptyNameParamater_shouldStoreEmptyNameProperty() {\n        \n        // Given\n        let name  = String()\n        let value = \"alue\"\n        \n        // When\n        sut = CLDVariable(name: name, value: value)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, value, \"Initilized object should contain an empty string as value property\")\n    }\n    func test_init_validStringParamatersAndNoNamePrefix_shouldStoreValidProperties() {\n        \n        // Given\n        let name  = \"name\"\n        let value = \"alue\"\n        \n        // When\n        sut = CLDVariable(name: name, value: value)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, value, \"Initilized object should contain a string as value property\")\n    }\n    func test_init_validStringParamaters_shouldStoreValidProperties() {\n        \n        // Given\n        let name  = \"$foo\"\n        let value = \"alue\"\n        \n        // When\n        sut = CLDVariable(name: name, value: value)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, value, \"Initilized object should contain a string as value property\")\n    }\n    func test_init_emptyNameParamaterIntValue_shouldStoreEmptyNameProperty() {\n        \n        // Given\n        let name  = String()\n        let value = 4\n        \n        // When\n        sut = CLDVariable(name: name, value: value)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, String(value), \"Initilized object should contain a string as value property\")\n    }\n    func test_init_validIntValue_shouldStoreValidProperties() {\n        \n        // Given\n        let name  = \"name\"\n        let value = 4\n        \n        // When\n        sut = CLDVariable(name: name, value: value)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, String(value), \"Initilized object should contain a string as value property\")\n    }\n    func test_init_emptyNameParamaterDoubleValue_shouldStoreEmptyNameProperty() {\n        \n        // Given\n        let name  = String()\n        let value = 3.14\n        \n        // When\n        sut = CLDVariable(name: name, value: value)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, String(value), \"Initilized object should contain a string as value property\")\n    }\n    func test_init_validDoubleValue_shouldStoreValidProperties() {\n        \n        // Given\n        let name  = \"name\"\n        let value = 3.14\n        \n        // When\n        sut = CLDVariable(name: name, value: value)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, String(value), \"Initilized object should contain a string as value property\")\n    }\n    \n    // MARK: - test initilization methods - values\n    func test_initWithValuesArray_emptyInputParamaters_shouldStoreEmptyProperties() {\n        \n        // Given\n        let name   =  String()\n        let values = [String]()\n        \n        // When\n        sut = CLDVariable(name: name, values: values)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name, CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, String(), \"Initilized object should contain an empty string as value property\")\n    }\n    func test_initWithValuesArray_emptyValueParamater_shouldStoreEmptyValueProperty() {\n        \n        // Given\n        let name   = \"name\"\n        let values = [String]()\n        \n        // When\n        sut = CLDVariable(name: name, values: values)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, String(), \"Initilized object should contain an empty string as value property\")\n    }\n    func test_initWithValuesArray_validOneValueArray_shouldStoreValidProperties() {\n        \n        // Given\n        let name   = \"foo\"\n        let values = [\"my\"]\n        let expectedResult = \"!my!\"\n        \n        // When\n        sut = CLDVariable(name: name, values: values)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, expectedResult, \"Initilized object should contain an encoded string as value property\")\n    }\n    func test_initWithValuesArray_validTwoValuesArray_shouldStoreValidProperties() {\n        \n        // Given\n        let name   = \"foo\"\n        let values = [\"my\",\"str\"]\n        let expectedResult = \"!my:str!\"\n        \n        // When\n        sut = CLDVariable(name: name, values: values)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, expectedResult, \"Initilized object should contain an encoded string as value property\")\n    }\n    func test_initWithValuesArray_validThreeValuesArray_shouldStoreValidProperties() {\n        \n        // Given\n        let name   = \"foo\"\n        let values = [\"my\",\"str\",\"ing\"]\n        let expectedResult = \"!my:str:ing!\"\n        \n        // When\n        sut = CLDVariable(name: name, values: values)\n        \n        // Then\n        XCTAssertNotNil(sut.name , \"Initilized object should contain a none nil name  property\")\n        XCTAssertNotNil(sut.value, \"Initilized object should contain a none nil value property\")\n        \n        XCTAssertEqual(sut.name , CLDVariable.variableNamePrefix + name, \"Name property should have a valid prefix\")\n        XCTAssertEqual(sut.value, expectedResult, \"Initilized object should contain an encoded string as value property\")\n    }\n    \n    // MARK: - test asString()\n    func test_asString_emptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let name  = String()\n        let value = String()\n        let expectedResult = String()\n        \n        // When\n        sut = CLDVariable(name: name, value: value)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString on an empty CLDVariable, should return an empty string\")\n    }\n    func test_asString_validParamaters_shouldReturnValidString() {\n        \n        // Given\n        let name  = \"$foo\"\n        let value = \"bar\"\n        let expectedResult = \"$foo_bar\"\n        \n        // When\n        sut = CLDVariable(name: name, value: value)\n        \n        let actualResult = sut.asString()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asString on a CLDVariable, should return a string\")\n    }\n    \n    // MARK: - test asParams()\n    func test_asParams_emptyInputParamaters_shouldReturnEmptyString() {\n        \n        // Given\n        let name  = String()\n        let value = String()\n        let expectedResult = [String:String]()\n        \n        // When\n        sut = CLDVariable(name: name, value: value)\n        \n        let actualResult = sut.asParams()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asParams, should build a paramater representation\")\n    }\n    func test_asParams_validParamaters_shouldReturnValidString() {\n        \n        // Given\n        let name   = \"foo\"\n        let values = [\"my\",\"str\",\"ing\"]\n        let expectedResult = [\"$foo\":\"!my:str:ing!\"]\n        \n        // When\n        sut = CLDVariable(name: name, values: values)\n        \n        let actualResult = sut.asParams()\n        \n        // Then\n        XCTAssertEqual(actualResult, expectedResult, \"Calling asParams, should build a paramater representation\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UIExtensions/CLDVideoPlayerTests.swift",
    "content": "//\n//  CLDVideoPlayerTests.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\nimport Cloudinary\nimport AVFoundation\nimport AVKit\n\nclass CLDVideoPlayerTests: UIBaseTest {\n\n    // MARK: - Tests\n\n    func testVideoLoadingAndSetFromURL() {\n        var videoLoadedAndSet = false\n        let videoPlayer = CLDVideoPlayer(url: \"https://testurl.com\")\n        if videoPlayer.currentItem != nil {\n            videoLoadedAndSet = true\n        }\n        XCTAssertTrue(videoLoadedAndSet)\n    }\n\n    func testInitializationWithValidData() {\n        let publicId = \"test_public_id\"\n        let transformation = CLDTransformation().setWidth(640).setHeight(480)\n\n        let player = CLDVideoPlayer(publicId: publicId, cloudinary: cloudinarySecured, transformation: transformation)\n\n        XCTAssertNotNil(player, \"CLDVideoPlayer should initialize with valid data.\")\n    }\n\n\n    func testPlaybackPauses() {\n        var publicId: String? = \"\"\n        let file = TestResourceType.dog.url\n        let params = CLDUploadRequestParams().setColors(true)\n        params.setResourceType(.video)\n\n        XCTAssertNotNil(publicId)\n        let player = CLDVideoPlayer(url: file)\n\n        // Assuming you have a test expectation for the video to pause.\n        let expectation = XCTestExpectation(description: \"Video should pause.\")\n\n        // Start playing and pause after 2 seconds.\n        player.play()\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {\n            player.pause()\n            expectation.fulfill()\n        }\n\n        wait(for: [expectation], timeout: 5.0)\n    }\n    \n    func testEventsManagerReceivesDurationValues() {\n        let eventsManager = VideoEventsManager()\n        \n        XCTAssertNoThrow({\n            eventsManager.sendLoadMetadataEvent(duration: 0)\n        }, \"Sending duration 0 should not crash\")\n        \n        XCTAssertNoThrow({\n            eventsManager.sendLoadMetadataEvent(duration: 10)\n        }, \"Sending valid duration should not crash\")\n        \n        XCTAssertNoThrow({\n            eventsManager.sendLoadMetadataEvent(duration: -1)\n        }, \"Events manager should handle any integer value\")\n        \n        XCTAssertNoThrow({\n            eventsManager.sendLoadMetadataEvent(duration: Int.max)\n        }, \"Events manager should handle large values\")\n    }\n    \n    func testDurationHandlingFlowIntegration() {\n        let expectation = XCTestExpectation(description: \"Duration flow should complete\")\n        \n        let player = CLDVideoPlayer(url: \"data:,\")\n        \n        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {\n            XCTAssertNoThrow({\n                _ = player.currentItem\n                _ = player.status\n            }, \"Accessing player properties should not crash\")\n            \n            XCTAssertNoThrow({\n                player.play()\n                player.pause()\n            }, \"Player methods should work after problematic URL\")\n            \n            expectation.fulfill()\n        }\n        \n        wait(for: [expectation], timeout: 2.0)\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UIExtensions/UIBaseTest.swift",
    "content": "//\n//  UIBaseTest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\nimport Cloudinary\nimport UIKit\n\nclass UIBaseTest: NetworkBaseTest {\n    \n    let url = \"https://res-1.cloudinary.com/cloudinary/image/asset/dpr_2.0/logo-e0df892053afd966cc0bfe047ba93ca4.png\"\n    \n    // MARK: - Setup\n    \n    override func setUp() {\n        super.setUp()\n        \n        cloudinary!.enableUrlCache = false\n        continueAfterFailure = false        \n    }\n    \n}\n"
  },
  {
    "path": "Example/Tests/UIExtensions/UIButtonTests.swift",
    "content": "//\n//  UIButtonTests.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n\nclass UIButtonTests: UIBaseTest {\n    \n    \n    // MARK: - Tests\n    \n    func testImageDownloadedAndSetFromURL() {\n        \n        let expectation = self.expectation(description: \"should succeed downloading and setting image.\")\n        \n        var imageDownloadedAndSet = false\n        let btn = TestButton { (image) in\n            if image != nil {\n                imageDownloadedAndSet = true\n            }\n            expectation.fulfill()\n        }\n        \n        btn.cldSetImage(url, forState: .normal, cloudinary: cloudinarySecured)\n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertTrue(imageDownloadedAndSet)\n        \n    }\n    \n    func testImageDownloadedAndSetFromPublicID() {\n        \n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var publicId: String?\n        uploadFile().response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"should succeed downloading and setting image.\")\n        \n        var imageDownloadedAndSet = false\n        let btn = TestButton { (image) in\n            if image != nil {\n                imageDownloadedAndSet = true\n            }\n            expectation.fulfill()\n        }\n        \n        btn.cldSetImage(publicId: pubId, cloudinary: cloudinarySecured, forState: .normal)\n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertTrue(imageDownloadedAndSet)\n        \n    }\n    \n    func testBackgroundImageDownloadedAndSetFromURL() {\n        \n        let expectation = self.expectation(description: \"should succeed downloading and setting image.\")\n        \n        var imageDownloadedAndSet = false\n        let btn = TestButton { (image) in\n            if image != nil {\n                imageDownloadedAndSet = true\n            }\n            expectation.fulfill()\n        }\n                \n        btn.cld_setBackgroundImage(url, forState: .normal, cloudinary: cloudinarySecured)\n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertTrue(imageDownloadedAndSet)\n        \n    }\n    \n    func testBackgroundImageDownloadedAndSetFromPublicID() {\n        \n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var publicId: String?\n        uploadFile().response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"should succeed downloading and setting image.\")\n        \n        var imageDownloadedAndSet = false\n        let btn = TestButton { (image) in\n            if image != nil {\n                imageDownloadedAndSet = true\n            }\n            expectation.fulfill()\n        }\n        \n        btn.cld_setBackgroundImage(publicId: pubId, cloudinary: cloudinarySecured, forState: .normal)\n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertTrue(imageDownloadedAndSet)\n        \n    }\n    \n    // MARK: - Helpers\n    \n    fileprivate class TestButton: UIButton {\n        \n        var imageSetListener: ((UIImage?) -> ())?\n        \n        init(imageSetListener: ((UIImage?) -> ())? = nil) {\n            super.init(frame: CGRect.zero)\n            self.imageSetListener = imageSetListener            \n        }\n        \n        required init?(coder aDecoder: NSCoder) {\n            fatalError(\"init(coder:) has not been implemented\")\n        }\n        \n        fileprivate override func setImage(_ image: UIImage?, for state: UIControl.State) {\n            super.setImage(image, for: state)\n            imageSetListener?(image)\n        }\n        \n        fileprivate override func setBackgroundImage(_ image: UIImage?, for state: UIControl.State) {\n            super.setBackgroundImage(image, for: state)\n            imageSetListener?(image)\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UIExtensions/UIImageViewTests.swift",
    "content": "//\n//  UIImageViewTests.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\nimport Cloudinary\n\nclass UIImageViewTests: UIBaseTest {\n        \n    // MARK: - Tests\n    \n    func testImageDownloadedAndSetFromURL() {\n        \n        let expectation = self.expectation(description: \"should succeed downloading and setting image.\")\n        \n        var imageDownloadedAndSet = false\n        let imageView = TestImageView { (image) in\n            if image != nil {\n                imageDownloadedAndSet = true\n            }   \n            expectation.fulfill()\n        }\n        imageView.cldSetImage(url, cloudinary: cloudinarySecured)\n        waitForExpectations(timeout: timeout, handler: nil)\n        XCTAssertTrue(imageDownloadedAndSet)\n    }\n\n    func testImageDownloadedWithUrlCache() {\n        let expectation = self.expectation(description: \"should succeed downloading and setting image.\")\n\n        var imageDownloadedAndSet = false\n        let imageView = TestImageView { (image) in\n            if image != nil {\n                imageDownloadedAndSet = true\n            }\n            expectation.fulfill()\n        }\n        cloudinarySecured.enableUrlCache = true\n        imageView.cldSetImage(url, cloudinary: cloudinarySecured)\n        waitForExpectations(timeout: timeout, handler: nil)\n        XCTAssertTrue(imageDownloadedAndSet)\n    }\n    \n    func testResponsiveImageDownloadedAndSetFromURL() {\n        let expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var publicId: String?\n        uploadFile().response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        let dpr = UIScreen.main.scale\n        \n        // Test auto_fill\n        // **************\n        var params = CLDResponsiveParams.autoFill().setStepSize(50).setMaxDimension(350).setMinDimension(100)\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 145, viewHeight: 172, expectedImageWidth: 150 * dpr, expectedImageHeight: 200 * dpr, label: \"fill, step size rounding\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 210, viewHeight: 142, expectedImageWidth: 250 * dpr, expectedImageHeight: 150 * dpr, label: \"fill, step size rounding\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 100, viewHeight: 100, expectedImageWidth: 100 * dpr, expectedImageHeight: 100 * dpr, label: \"fill, step size rounding, equal to min\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 10, viewHeight: 10, expectedImageWidth: 100 * dpr, expectedImageHeight: 100 * dpr, label: \"fill, step size rounding, below minimum\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 10000, viewHeight: 10000, expectedImageWidth: 350 * dpr, expectedImageHeight: 350 * dpr, label: \"fill, step size rounding, above maximum\")\n        \n        // Test fit\n        // ********\n        params = CLDResponsiveParams.fit().setStepSize(50).setMaxDimension(350).setMinDimension(100)\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 100, viewHeight: 300, expectedImageWidth: 100 * dpr, expectedImageHeight: 100 * dpr, label: \"fit, step size rounding, equal to min\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 210, viewHeight: 190, expectedImageWidth: 200 * dpr, expectedImageHeight: 200 * dpr, label: \"fit, step size rounding\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 300, viewHeight: 100, expectedImageWidth: 100 * dpr, expectedImageHeight: 100 * dpr, label: \"fit, step size rounding, equal to min\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 1, viewHeight: 1000, expectedImageWidth: 100 * dpr, expectedImageHeight: 100 * dpr, label: \"fit, step size rounding, below min\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 1000, viewHeight: 1, expectedImageWidth: 100 * dpr, expectedImageHeight: 100 * dpr, label: \"fit, step size rounding, below min\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 200, viewHeight: 10000, expectedImageWidth: 200 * dpr, expectedImageHeight: 200 * dpr, label: \"fit, step size rounding, above max\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 20000, viewHeight: 200, expectedImageWidth: 200 * dpr, expectedImageHeight: 200 * dpr, label: \"fit, step size rounding, above max\")\n        validateResponsiveGeneration(publicId: pubId, params: params, viewWidth: 200, viewHeight: 200, expectedImageWidth: 200 * dpr, expectedImageHeight: 200 * dpr, label: \"fit, step size rounding, equal to step size\")\n    }\n    \n    func testImageDownloadedAndSetFromPublicID() {\n        \n        var expectation = self.expectation(description: \"Upload should succeed\")\n        \n        var publicId: String?\n        uploadFile().response({ (result, error) in\n            publicId = result?.publicId\n            expectation.fulfill()\n        })\n        \n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        guard let pubId = publicId else {\n            XCTFail(\"Public ID should not be nil at this point\")\n            return\n        }\n        \n        expectation = self.expectation(description: \"should succeed downloading and setting image.\")\n        \n        var imageDownloadedAndSet = false\n        let imageView = TestImageView { (image) in\n            if image != nil {\n                imageDownloadedAndSet = true\n            }\n            expectation.fulfill()\n        }\n        \n        imageView.cldSetImage(publicId: pubId, cloudinary: cloudinarySecured)\n        waitForExpectations(timeout: timeout, handler: nil)\n        \n        XCTAssertTrue(imageDownloadedAndSet)\n        \n    }\n    \n    // MARK: - Helpers\n    \n    private class TestImageView: CLDUIImageView {\n        \n        var imageSetListener: ((UIImage?) -> ())?\n        \n        override var image: UIImage? {\n            didSet {\n                imageSetListener?(image)\n            }\n        }\n        \n        init(imageSetListener: ((UIImage?) -> ())? = nil) {\n            super.init(frame: CGRect.zero)\n            self.imageSetListener = imageSetListener\n        }\n        \n        required init?(coder aDecoder: NSCoder) {\n            fatalError(\"init(coder:) has not been implemented\")\n        }        \n    }\n    \n    private func validateResponsiveGeneration(publicId: String, params: CLDResponsiveParams, viewWidth: Int, viewHeight: Int, expectedImageWidth: CGFloat, expectedImageHeight: CGFloat, label: String) {\n        let expectation = self.expectation(description: \"Should succeed fetching image with correct dimensions for \\(label)\")\n\n        var imageDownloadedAndSet = false\n        let imageView = TestImageView { (image) in\n            if image != nil && image!.size.width == expectedImageWidth && image!.size.height == expectedImageHeight {\n                imageDownloadedAndSet = true\n            }\n            expectation.fulfill()\n        }\n        \n        imageView.frame = CGRect(x: 0, y: 0, width: viewWidth, height: viewHeight)\n        imageView.layoutMargins.bottom = 0\n        imageView.layoutMargins.top = 0\n        imageView.layoutMargins.left = 0\n        imageView.layoutMargins.right = 0\n        imageView.layoutSubviews()\n        imageView.cldSetImage(publicId: publicId, cloudinary: cloudinarySecured, responsiveParams: params)\n\n        waitForExpectations(timeout: timeout, handler: nil)\n        XCTAssertTrue(imageDownloadedAndSet)\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UIExtensions/Video Analytics/VideoEventsManagerTests.swift",
    "content": "//\n//  VideoEventsManagerTests.swift\n//  Cloudinary_Tests\n//\n//  Created by Adi Mizrahi on 14/12/2023.\n//  Copyright © 2023 CocoaPods. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport Cloudinary\nfinal class VideoEventsManagerTests: XCTestCase {\n    var videoEventManager: VideoEventsManager!\n\n    override func setUp() {\n        super.setUp()\n        videoEventManager = VideoEventsManager()\n        // Additional setup if needed\n    }\n\n    override func tearDown() {\n        videoEventManager = nil\n        super.tearDown()\n    }\n\n    func testAddingEventsToQueue() {\n        let initialQueueCount = videoEventManager.eventQueue.count\n\n        // Call functions that add events to the queue\n\n        // Example:\n        videoEventManager.sendViewStartEvent(videoUrl: \"testURL\")\n        videoEventManager.sendViewEndEvent()\n        videoEventManager.sendPlayEvent()\n\n        XCTAssertEqual(videoEventManager.eventQueue.count, initialQueueCount + 3)\n    }\n\n    func testSendingEvents() {\n        // Create an expectation for async testing\n        let expectation = XCTestExpectation(description: \"Events sent successfully\")\n\n        // Assuming you have mock URLSession or use a testable endpoint to avoid actual network calls\n        videoEventManager.CLD_ANALYTICS_ENDPOINT_DEVELOPMENT_URL = \"http://localhost:3001/mock_events\" // Change to a mock endpoint\n\n        // Add events to the queue\n        videoEventManager.sendViewStartEvent(videoUrl: \"testURL\")\n        videoEventManager.sendViewEndEvent()\n        videoEventManager.sendPlayEvent()\n        videoEventManager.sendEvents()\n        // Simulate sending events\n        //           videoEventManager.sendEvents()\n\n        // Wait for a certain amount of time or use a completion block to verify successful sending\n        DispatchQueue.main.asyncAfter(deadline: .now() + 8.0) {\n            // Assuming the response is received\n            // Check if event queue is empty after sending\n            XCTAssertTrue(self.videoEventManager.eventQueue.isEmpty)\n\n            expectation.fulfill()\n        }\n\n        wait(for: [expectation], timeout: 16.0) // Wait for an expectation\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UIExtensions/Video Analytics/VideoEventsTests.swift",
    "content": "//\n//  VideoEventsTests.swift\n//  Cloudinary_Tests\n//\n//  Created by Adi Mizrahi on 18/12/2023.\n//  Copyright © 2023 CocoaPods. All rights reserved.\n//\n\nimport XCTest\nimport Cloudinary\npublic class VideoEventTests: XCTestCase {\n\n    func testVideoViewStartEventInitialization() {\n        let videoUrl = \"https://www.example.com/video.mp4\"\n        let trackingData = [\"cloudName\": \"exampleCloud\", \"publicId\": \"abc123\"]\n        let providedData = [\"key\": \"value\"]\n\n        let event = VideoViewStartEvent(videoUrl: videoUrl, trackingData: trackingData, providedData: providedData)\n\n        XCTAssertEqual(event.eventName, EventNames.viewStart.rawValue)\n        XCTAssertEqual(event.eventDetails[VideoEventJSONKeys.trackingType.rawValue] as? String, TrackingType.auto.rawValue)\n        XCTAssertEqual(event.eventDetails[VideoEventJSONKeys.videoUrl.rawValue] as? String, videoUrl)\n\n        if let customerData = event.eventDetails[VideoEventJSONKeys.customerData.rawValue] as? [String: Any],\n           let videoData = customerData[VideoEventJSONKeys.videoData.rawValue] as? [String: Any] {\n            XCTAssertEqual(videoData[VideoEventJSONKeys.cloudName.rawValue] as? String, trackingData[\"cloudName\"])\n            XCTAssertEqual(videoData[VideoEventJSONKeys.publicId.rawValue] as? String, trackingData[\"publicId\"])\n        }\n\n        if let providedDataObject = event.eventDetails[VideoEventJSONKeys.providedData.rawValue] as? [String: Any] {\n            XCTAssertEqual(providedDataObject[\"key\"] as? String, providedData[\"key\"])\n        }\n    }\n\n    func testVideoLoadMetadataEventInitialization() {\n        let duration = 120\n\n        let event = VideoLoadMetadata(duration: duration)\n\n        XCTAssertEqual(event.eventName, EventNames.loadMetadata.rawValue)\n        XCTAssertEqual(event.eventDetails[VideoEventJSONKeys.trackingType.rawValue] as? String, TrackingType.auto.rawValue)\n        XCTAssertEqual(event.eventDetails[VideoEventJSONKeys.videoDuration.rawValue] as? Int, duration)\n    }\n\n    func testVideoViewEndEventInitialization() {\n        let providedData = [\"key\": \"value\"]\n\n        let event = VideoViewEnd(providedData: providedData)\n\n        XCTAssertEqual(event.eventName, EventNames.viewEnd.rawValue)\n        XCTAssertEqual(event.eventDetails[VideoEventJSONKeys.trackingType.rawValue] as? String, TrackingType.auto.rawValue)\n\n        if let providedDataObject = event.eventDetails[VideoEventJSONKeys.providedData.rawValue] as? [String: Any] {\n            XCTAssertEqual(providedDataObject[\"key\"] as? String, providedData[\"key\"])\n        }\n    }\n\n    func testVideoPlayEventInitialization() {\n        let providedData = [\"key\": \"value\"]\n\n        let event = VideoPlayEvent(providedData: providedData)\n\n        XCTAssertEqual(event.eventName, EventNames.play.rawValue)\n\n        if let providedDataObject = event.eventDetails[VideoEventJSONKeys.providedData.rawValue] as? [String: Any] {\n            XCTAssertEqual(providedDataObject[\"key\"] as? String, providedData[\"key\"])\n        }\n    }\n\n    func testVideoPauseEventInitialization() {\n        let providedData = [\"key\": \"value\"]\n\n        let event = VideoPauseEvent(providedData: providedData)\n\n        XCTAssertEqual(event.eventName, EventNames.pause.rawValue)\n\n        if let providedDataObject = event.eventDetails[VideoEventJSONKeys.providedData.rawValue] as? [String: Any] {\n            XCTAssertEqual(providedDataObject[\"key\"] as? String, providedData[\"key\"])\n        }\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploadWidgetHelpersTests/UploaderWidgetAssetContainerTests.swift",
    "content": "//\n//  UploaderWidgetAssetContainerTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\nimport AVKit\n\nclass UploaderWidgetAssetContainerTests: NetworkBaseTest {\n    \n    var sut: CLDWidgetAssetContainer!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - test init\n    func test_init_image_shouldStoreInputValues() {\n        \n        // Given\n        let image = UIImage()\n    \n        // When\n        sut = CLDWidgetAssetContainer(originalImage: image, editedImage: image)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.originalImage, \"object's properties should store value from init call\")\n        XCTAssertNotNil(sut.editedImage, \"object's properties should store value from init call\")\n        XCTAssertEqual (sut.originalImage, image, \"object's properties should store value from init call\")\n        XCTAssertEqual (sut.editedImage, image, \"object's properties should store value from init call\")\n        XCTAssertNil   (sut.originalVideo, \"video should be nil\")\n        XCTAssertNotNil(sut.presentationImage, \"presentationImage should be created in the object's init\")\n        XCTAssertEqual (sut.assetType, .image ,\"assetType should be created in the object's init\")\n    }\n    func test_init_localImages_shouldStoreInputValues() {\n        \n        // Given\n        let originalImage = getImage(.borderCollie)\n        let editedImage   = getImage(.logo)\n    \n        // When\n        sut = CLDWidgetAssetContainer(originalImage: originalImage, editedImage: editedImage)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.originalImage, \"object's properties should store value from init call\")\n        XCTAssertNotNil(sut.editedImage, \"object's properties should store value from init call\")\n        XCTAssertEqual (sut.originalImage, originalImage, \"object's properties should store value from init call\")\n        XCTAssertEqual (sut.editedImage, editedImage, \"object's properties should store value from init call\")\n        XCTAssertNil   (sut.originalVideo, \"video should be nil\")\n        XCTAssertNotNil(sut.presentationImage, \"presentationImage should be created in the object's init\")\n        XCTAssertEqual (sut.assetType, .image ,\"assetType should be created in the object's init\")\n    }\n    func test_init_localVideoUrl_shouldStoreInputValues() {\n        \n        // Given\n        let videoUrl = TestResourceType.dog.url\n        \n        // When\n        sut = CLDWidgetAssetContainer(videoUrl: videoUrl)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNil   (sut.originalImage, \"image should be nil\")\n        XCTAssertNil   (sut.editedImage, \"image should be nil\")\n        XCTAssertNotNil(sut.originalVideo, \"object's properties should store value from init call\")\n        XCTAssertNotNil(sut.presentationImage, \"presentationImage should be created in the object's init\")\n        XCTAssertEqual (sut.assetType, .video ,\"assetType should be created in the object's init\")\n    }\n    func test_init_localVideoItem_shouldStoreInputValues() {\n        \n        // Given\n        let videoItem = getVideo(.dog)\n        \n        // When\n        sut = CLDWidgetAssetContainer(videoItem: videoItem)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNil   (sut.originalImage, \"image should be nil\")\n        XCTAssertNil   (sut.editedImage, \"image should be nil\")\n        XCTAssertNotNil(sut.originalVideo, \"object's properties should store value from init call\")\n        XCTAssertEqual (sut.originalVideo, videoItem, \"object's properties should store value from init call\")\n        XCTAssertNotNil(sut.presentationImage, \"presentationImage should be created in the object's init\")\n        XCTAssertEqual (sut.assetType, .video ,\"assetType should be created in the object's init\")\n    }\n    \n    // MARK: - test input\n    func test_updateValues_localImages_shouldUpdateInputValues() {\n        \n        // Given\n        let initialImage = getImage(.borderCollie)\n        let newImage     = getImage(.logo)\n    \n        // When\n        sut             = CLDWidgetAssetContainer(originalImage: initialImage, editedImage: initialImage)\n        sut.editedImage = newImage\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertEqual (sut.originalImage, initialImage, \"object's properties should store value from init call\")\n        XCTAssertEqual (sut.editedImage, newImage, \"object's properties should update its value\")\n    }\n    \n    func test_thumbnailCreation_localVideo_shouldCreateExpectedThumbnail() {\n        \n        // Given\n        let videoItem = getVideo(.dog)\n        let knownSize = CGSize.init(width: 854, height: 480)\n    \n        // When\n        sut = CLDWidgetAssetContainer(videoItem: videoItem)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertEqual (sut.presentationImage.size, knownSize, \"object's properties should store value from init call\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploadWidgetHelpersTests/UploaderWidgetConfigurationTests.m",
    "content": "//\n//  ObjcUploaderWidgetConfigurationTests.m\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n\n@interface ObjcUploaderWidgetConfigurationTests : XCTestCase\n@property (nonatomic, strong, nullable) CLDWidgetConfiguration* sut;\n@end\n\n@implementation ObjcUploaderWidgetConfigurationTests\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n}\n- (void)tearDown {\n    [super tearDown];\n    self.sut = nil;\n}\n\n// MARK: - test initilization methods\n- (void)test_init_falseInputParamaters_shouldStoreInputValues {\n      \n    // Given\n    BOOL allowRotate                            = false;\n    AspectRatioLockState initialAspectLockState = AspectRatioLockStateDisabled;\n    CLDUploadType* uploadType                      = [[CLDUploadType alloc] initWithSigned:false preset:nil];\n    \n    // When\n    self.sut = [[CLDWidgetConfiguration alloc] initWithAllowRotate:allowRotate  initialAspectLockState:initialAspectLockState uploadType:uploadType];\n    \n    // Then\n    XCTAssertNotNil(self.sut, \"object should be initialized\");\n    XCTAssertFalse (self.sut.allowRotate, \"object's properties should store value from init call\");\n    XCTAssertEqual (self.sut.initialAspectLockState, initialAspectLockState, \"object's properties should store value from init call\");\n    XCTAssertEqual (self.sut.uploadType, uploadType, \"object's properties should store value from init call\");\n}\n- (void)test_init_mixInputParamaters_shouldStoreInputValues {\n      \n    // Given\n    BOOL allowRotate                            = true;\n    AspectRatioLockState initialAspectLockState = AspectRatioLockStateEnabledAndOn;\n    CLDUploadType* uploadType                      = [[CLDUploadType alloc] initWithSigned:true preset:@\"preset\"];\n    \n    // When\n    self.sut = [[CLDWidgetConfiguration alloc] initWithAllowRotate:allowRotate initialAspectLockState:initialAspectLockState uploadType:uploadType];\n    \n    // Then\n    XCTAssertNotNil(self.sut, \"object should be initialized\");\n    XCTAssertTrue (self.sut.allowRotate, \"object's properties should store value from init call\");\n    XCTAssertEqual (self.sut.initialAspectLockState, initialAspectLockState, \"object's properties should store value from init call\");\n    XCTAssertEqual (self.sut.uploadType, uploadType, \"object's properties should store value from init call\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploadWidgetHelpersTests/UploaderWidgetConfigurationTests.swift",
    "content": "//\n//  UploaderWidgetConfigurationTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass UploaderWidgetConfigurationTests: XCTestCase {\n    \n    var sut: CLDWidgetConfiguration!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - test initilization methods\n    func test_init_emptyInputParamaters_shouldStoreDefaultValues() {\n        \n        // When\n        sut = CLDWidgetConfiguration()\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertTrue  (sut.allowRotate, \"allowRotate default value should be true\")\n        XCTAssertEqual (sut.initialAspectLockState, CLDWidgetConfiguration.AspectRatioLockState.enabledAndOff, \"initialAspectLockState default value should be enabledAndOff\")\n        XCTAssertTrue  (sut.uploadType.signed, \"uploadType.signed default value should be true\")\n        XCTAssertNil   (sut.uploadType.preset, \"uploadType.preset default value should be nil\")\n    }\n    func test_init_falseInputParamaters_shouldStoreInputValues() {\n        \n        // Given\n        let allowRotate = false\n        let initialAspectLockState = CLDWidgetConfiguration.AspectRatioLockState.disabled\n        let uploadType: CLDUploadType = CLDUploadType(signed: false, preset: \"preset\")\n    \n        // When\n        sut = CLDWidgetConfiguration.init(allowRotate: allowRotate, initialAspectLockState: initialAspectLockState, uploadType: uploadType)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertFalse (sut.allowRotate, \"object's properties should store value from init call\")\n        XCTAssertEqual (sut.initialAspectLockState, initialAspectLockState, \"object's properties should store value from init call\")\n        XCTAssertEqual (sut.uploadType, uploadType, \"object's properties should store value from init call\")\n    }\n    func test_init_mixInputParamaters_shouldStoreInputValues() {\n        \n        // Given\n        let allowRotate            = true\n        let initialAspectLockState = CLDWidgetConfiguration.AspectRatioLockState.enabledAndOn\n        let uploadType      = CLDUploadType(signed: true, preset: nil)\n        \n        // When\n        sut = CLDWidgetConfiguration(allowRotate: allowRotate, initialAspectLockState: initialAspectLockState, uploadType: uploadType)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertTrue  (sut.allowRotate, \"object's properties should store value from init call\")\n        XCTAssertEqual (sut.initialAspectLockState, initialAspectLockState, \"object's properties should store value from init call\")\n        XCTAssertEqual (sut.uploadType, uploadType, \"object's properties should store value from init call\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploadWidgetVideoTests/UploaderWidgetVideoControlsTests.swift",
    "content": "//\n//  UploaderWidgetVideoControlsTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\nimport AVKit\n\nclass UploaderWidgetVideoControlsTests: NetworkBaseTest, CLDVideoControlsViewDelegate {\n    \n    var sut: CLDVideoControlsView!\n    \n    func pausePressedOnVideoControls(_ videoControls: CLDVideoControlsView) {}\n    func playPressedOnVideoControls(_ videoControls: CLDVideoControlsView) {}\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - init\n    func test_init_shouldCreateElement() {\n        \n        // Given\n        let frame = CGRect.zero\n        \n        // When\n        sut = CLDVideoControlsView(frame: frame, delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.playPauseButton, \"object should be initialized\")\n        XCTAssertNotNil(sut.visibilityTimer, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"object should be initialized\")\n        XCTAssertNotNil(sut.currentState, \"object should be initialized\")\n        XCTAssertNotNil(sut.shownAndPlayingState, \"object should be initialized\")\n        XCTAssertNotNil(sut.shownAndPausedState, \"object should be initialized\")\n        XCTAssertNotNil(sut.hiddenAndPlayingState, \"object should be initialized\")\n        XCTAssertNotNil(sut.hiddenAndPausedState, \"object should be initialized\")\n    }\n    \n    func test_init_noDelegate_shouldCreateElement() {\n        \n        // Given\n        let frame = CGRect.zero\n        \n        // When\n        sut = CLDVideoControlsView(frame: frame, delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.playPauseButton, \"object should be initialized\")\n        XCTAssertNotNil(sut.visibilityTimer, \"object should be initialized\")\n        XCTAssertNil   (sut.delegate, \"object should not be initialized\")\n        XCTAssertNotNil(sut.currentState, \"object should be initialized\")\n        XCTAssertNotNil(sut.shownAndPlayingState, \"object should be initialized\")\n        XCTAssertNotNil(sut.shownAndPausedState, \"object should be initialized\")\n        XCTAssertNotNil(sut.hiddenAndPlayingState, \"object should be initialized\")\n        XCTAssertNotNil(sut.hiddenAndPausedState, \"object should be initialized\")\n    }\n    \n    // MARK: - states\n    func test_initialState_shownAndPlayingState_shouldBeEqualToExpectedState() {\n        \n        // Given\n        let frame = CGRect.zero\n        \n        // When\n        sut = CLDVideoControlsView(frame: frame, delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.currentState, \"object should be initialized\")\n        XCTAssertEqual (sut.currentState as? CLDVideoShownAndPlayingState, sut.shownAndPlayingState as? CLDVideoShownAndPlayingState, \"objects should be equal\")\n    }\n    \n    func test_updateState_shownAndPausedState_shouldUpdateState() {\n        \n        // Given\n        let frame = CGRect.zero\n        \n        // When\n        sut = CLDVideoControlsView(frame: frame, delegate: nil)\n        sut.setNewState(newState: sut.shownAndPausedState)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.currentState, \"object should be initialized\")\n        XCTAssertEqual (sut.currentState as? CLDVideoShownAndPausedState, sut.shownAndPausedState as? CLDVideoShownAndPausedState,\"objects should be equal\")\n    }\n    func test_updateState_hiddenAndPlayingState_shouldUpdateState() {\n        \n        // Given\n        let frame = CGRect.zero\n        \n        // When\n        sut = CLDVideoControlsView(frame: frame, delegate: nil)\n        sut.setNewState(newState: sut.hiddenAndPlayingState)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.currentState, \"object should be initialized\")\n        XCTAssertEqual (sut.currentState as? CLDVideoHiddenAndPlayingState, sut.hiddenAndPlayingState as? CLDVideoHiddenAndPlayingState,\"objects should be equal\")\n    }\n    func test_updateState_hiddenAndPausedState_shouldUpdateState() {\n        \n        // Given\n        let frame = CGRect.zero\n        \n        // When\n        sut = CLDVideoControlsView(frame: frame, delegate: nil)\n        sut.setNewState(newState: sut.hiddenAndPausedState)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.currentState, \"object should be initialized\")\n        XCTAssertEqual (sut.currentState as? CLDVideoShownAndPausedState, sut.hiddenAndPausedState as? CLDVideoShownAndPausedState,\"objects should be equal\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploadWidgetVideoTests/UploaderWidgetVideoDisplayLinkTests.swift",
    "content": "//\n//  UploaderWidgetVideoDisplayLinkTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\nimport AVKit\n\nclass UploaderWidgetVideoDisplayLinkTests: NetworkBaseTest, CLDDisplayLinkObserverDelegate {\n    \n    var sut: CLDDisplayLinkObserver!\n    \n    func displayLinkObserverDidTick(_ linkObserver: CLDDisplayLinkObserver) {}\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - init\n    func test_init_shouldCreateElement() {\n                \n        // When\n        sut = CLDDisplayLinkObserver(delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.tickerTimestamp, \"object should be initialized\")\n    }\n    func test_init_noDelegate_shouldCreateElement() {\n                \n        // When\n        sut = CLDDisplayLinkObserver(delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.tickerTimestamp, \"object should be initialized\")\n    }\n    \n    // MARK: - internal methods\n    func test_startTicker_shouldStartTheTickerLogic() {\n                \n        // When\n        sut = CLDDisplayLinkObserver(delegate: nil)\n        sut.startTicker()\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.tickerTimestamp, \"object should be initialized\")\n        XCTAssertNotNil(sut.displayLinkTicker, \"object should be initialized\")\n    }\n    func test_stopTicker_shouldStopTheTickerLogic() {\n                \n        // When\n        sut = CLDDisplayLinkObserver(delegate: nil)\n        sut.startTicker()\n        sut.stopTicker()\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.tickerTimestamp, \"object should be initialized\")\n        XCTAssertNil   (sut.displayLinkTicker, \"object should not be initialized\")\n    }\n    \n    func test_isValid_notRunning_shouldRepresentCurrentTickerState() {\n                \n        // When\n        sut = CLDDisplayLinkObserver(delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.tickerTimestamp, \"object should be initialized\")\n        XCTAssertFalse (sut.isValid(), \"object should not be valid\")\n    }\n    func test_isValid_running_shouldRepresentCurrentTickerState() {\n                \n        // When\n        sut = CLDDisplayLinkObserver(delegate: nil)\n        sut.startTicker()\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.tickerTimestamp, \"object should be initialized\")\n        XCTAssertTrue  (sut.isValid(), \"object should be valid\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploadWidgetVideoTests/UploaderWidgetVideoPlayerTests.swift",
    "content": "//\n//  UploaderWidgetVideoPlayerTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\nimport AVKit\n\nclass UploaderWidgetVideoPlayerTests: NetworkBaseTest {\n    \n    var sut: CLDVideoPlayerView!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - init\n    func test_init_shouldCreateElement() {\n        \n        // Given\n        let frame = CGRect.zero\n        \n        // When\n        sut = CLDVideoPlayerView(frame: frame)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.playerLayer, \"object should be initialized\")\n    }\n    \n    // MARK: - update\n    func test_init_addPlayer_shouldCreateElement() {\n        \n        // Given\n        let frame  = CGRect.zero\n        let player = AVPlayer()\n        \n        // When\n        sut = CLDVideoPlayerView(frame: frame)\n        sut.player = player\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertEqual (sut.player, player, \"objects should be equal\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploadWidgetVideoTests/UploaderWidgetVideoViewTests.swift",
    "content": "//\n//  UploaderWidgetVideoViewTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\nimport AVKit\n\nclass UploaderWidgetVideoViewTests: NetworkBaseTest {\n    \n    var sut: CLDVideoView!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - init\n    func test_init_shouldCreateElement() {\n        \n        // Given\n        let frame      = CGRect.zero\n        let playerItem = getVideo(.dog)\n        let isMuted    = true\n        \n        // When\n        sut = CLDVideoView(frame: frame, playerItem: playerItem, isMuted: isMuted)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.videoControlsView, \"object should be initialized\")\n        XCTAssertNotNil(sut.videoPlayerView, \"object should be initialized\")\n        XCTAssertNotNil(sut.player, \"object should be initialized\")\n        XCTAssertEqual (sut.player.currentItem, playerItem, \"objects should be equal\")\n    }\n    \n    func test_init_noVideo_shouldCreateElement() {\n        \n        // Given\n        let frame      = CGRect.zero\n        let isMuted    = true\n        \n        // When\n        sut = CLDVideoView(frame: frame, playerItem: nil, isMuted: isMuted)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.videoControlsView, \"object should be initialized\")\n        XCTAssertNotNil(sut.videoPlayerView, \"object should be initialized\")\n        XCTAssertNotNil(sut.player, \"object should be initialized\")\n        XCTAssertNil   (sut.player.currentItem, \"object should not be initialized\")\n    }\n    \n    // MARK: - update\n    func test_replace_playerItem_shouldUpdateElements() {\n        \n        // Given\n        let frame             = CGRect.zero\n        let playerItem        = getVideo(.dog)\n        let playerItemUpdated = getVideo(.dog2)\n        let isMuted           = true\n        \n        // When\n        sut = CLDVideoView(frame: frame, playerItem: playerItem, isMuted: isMuted)\n        sut.replaceCurrentItem(with: playerItemUpdated)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertEqual (sut.player.currentItem, playerItemUpdated, \"objects should be equal\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploaderWidgetEditTests/UploaderWidgetEditViewControllerTests.swift",
    "content": "//\n//  UploaderWidgetEditViewControllerTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass UploaderWidgetEditViewControllerTests: NetworkBaseTest, CLDWidgetEditDelegate {\n    \n    var sut: CLDWidgetEditViewController!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - Helper\n    func createImageContainer() -> CLDWidgetAssetContainer {\n        return CLDWidgetAssetContainer(originalImage: getImage(.logo), editedImage: getImage(.logo))\n    }\n    \n    // MARK: - delegate\n    func widgetEditViewController(_ controller: CLDWidgetEditViewController, didFinishEditing image: CLDWidgetAssetContainer) {\n        print(\"delegate didFinishEditing\")\n    }\n    func widgetEditViewControllerDidReset(_ controller: CLDWidgetEditViewController) {\n        print(\"delegate didReset\")\n    }\n    func widgetEditViewControllerDidCancel(_ controller: CLDWidgetEditViewController) {\n        print(\"delegate didCancel\")\n    }\n    \n    // MARK: - test init\n    func test_init_emptyImage_shouldCreateObject() {\n        \n        // Given\n        let image = CLDWidgetAssetContainer(originalImage: UIImage(), editedImage: UIImage())\n        \n        // When\n        sut = CLDWidgetEditViewController(image: image)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n    }\n    func test_init_emptyProperties_shouldCreateObject() {\n        \n        // Given\n        let image = CLDWidgetAssetContainer(originalImage: UIImage(), editedImage: UIImage())\n        \n        // When\n        sut = CLDWidgetEditViewController(image: image, configuration: nil, delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n    }\n    func test_init_properties_shouldCreateObjectWithProperties() {\n        \n        // Given\n        let image = createImageContainer()\n        let configuration = CLDWidgetConfiguration(allowRotate: true, initialAspectLockState: .enabledAndOn)\n        \n        // When\n        sut = CLDWidgetEditViewController(image: image, configuration: configuration, delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"delegate should be initialized\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n        XCTAssertEqual (sut.image, image, \"objects should be equal\")\n    }\n    func test_init_delegateAfterInit_shouldCreateObjectAndUpdateDelegate() {\n        \n        // Given\n        let image = createImageContainer()\n        let configuration = CLDWidgetConfiguration(allowRotate: true, initialAspectLockState: .enabledAndOn)\n        \n        // When\n        sut = CLDWidgetEditViewController(image: image, configuration: configuration, delegate: nil)\n        sut.delegate = self\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"delegate should be initialized\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n        XCTAssertEqual (sut.image, image, \"objects should be equal\")\n    }\n    \n    // MARK: - test views\n    func test_createView_shouldCreateObjectWithUIElements() {\n\n        // Given\n        let image = createImageContainer()\n\n        // When\n        sut = CLDWidgetEditViewController(image: image)\n        let _ = sut.view\n\n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.buttonsView, \"object should be initialized\")\n        XCTAssertNotNil(sut.cancelButton, \"object should be initialized\")\n        XCTAssertNotNil(sut.rotateButton, \"object should be initialized\")\n        XCTAssertNotNil(sut.doneButton, \"object should be initialized\")\n        XCTAssertNotNil(sut.cropView, \"object should be initialized\")\n    }\n    func test_createView_shouldCreateCustomButtonsInSameSuperview() {\n\n        // Given\n        let image = createImageContainer()\n\n        // When\n        sut = CLDWidgetEditViewController(image: image)\n        let _ = sut.view\n\n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertEqual (sut.cancelButton.buttonType, .custom, \"objects should be equal\")\n        XCTAssertEqual (sut.rotateButton.buttonType, .custom, \"objects should be equal\")\n        XCTAssertEqual (sut.doneButton.buttonType, .custom, \"objects should be equal\")\n        XCTAssertEqual (sut.cancelButton.superview, sut.buttonsView, \"objects should be equal\")\n        XCTAssertEqual (sut.rotateButton.superview, sut.buttonsView, \"objects should be equal\")\n        XCTAssertEqual (sut.doneButton.superview, sut.buttonsView, \"objects should be equal\")\n    }\n    func test_createView_allowRotateTrue_rotateButtonShouldBeVisible() {\n\n        // Given\n        let image = createImageContainer()\n        let configuration = CLDWidgetConfiguration(allowRotate: true, initialAspectLockState: .enabledAndOn)\n\n        // When\n        sut = CLDWidgetEditViewController(image: image, configuration: configuration)\n        let _ = sut.view\n\n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertFalse (sut.rotateButton.isHidden, \"rotate button should be visible when allowRotate = true\")\n    }\n    func test_createView_allowRotateFalse_rotateButtonShouldBeHidden() {\n\n        // Given\n        let image = createImageContainer()\n        let configuration = CLDWidgetConfiguration(allowRotate: false, initialAspectLockState: .enabledAndOn)\n\n        // When\n        sut = CLDWidgetEditViewController(image: image, configuration: configuration)\n        let _ = sut.view\n\n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertTrue (sut.rotateButton.isHidden, \"rotate button should be hidden when allowRotate = false\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploaderWidgetPreviewTests/UploaderWidgetCollectionCellTests.swift",
    "content": "//\n//  UploaderWidgetCollectionCellTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass UploaderWidgetCollectionCellTests: NetworkBaseTest {\n    \n    var sut: CLDWidgetPreviewCollectionCell!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - test init\n    func test_init_shouldCreateElements() {\n        \n        // Given\n        let frame = CGRect(x: 0, y: 0, width: 400, height: 300)\n    \n        // When\n        sut = CLDWidgetPreviewCollectionCell(frame: frame)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.imageView, \"object's elements should be initialized\")\n        XCTAssertEqual (sut.frame, frame, \"object's frame should be set\")\n    }\n    func test_init_imageViewFrame_shouldSetImageViewFrame() {\n        \n        // Given\n        let frame = CGRect(x: 0, y: 0, width: 400, height: 300)\n\n        // When\n        sut = CLDWidgetPreviewCollectionCell(frame: frame)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.imageView, \"object's elements should be initialized\")\n        XCTAssertEqual (sut.imageView.frame, frame, \"object's imageView frame should be set\")\n    }\n    func test_init_imageViewImage_shouldSetImageViewImage() {\n        \n        // Given\n        let image = UIImage()\n        let frame = CGRect(x: 0, y: 0, width: 400, height: 300)\n        \n        // When\n        sut = CLDWidgetPreviewCollectionCell(frame: frame)\n        sut.imageView.image = image\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.imageView, \"object's elements should be initialized\")\n        XCTAssertEqual (sut.imageView.image, image, \"object's imageView image should be set\")\n    }\n    \n    // MARK: - test update\n    func test_update_imageViewImage_shouldUpdateImageViewImage() {\n        \n        // Given\n        let initialImage = getImage(.logo)\n        let updatedImage = getImage(.borderCollie)\n        let frame        = CGRect(x: 0, y: 0, width: 400, height: 300)\n        \n        // When\n        sut = CLDWidgetPreviewCollectionCell(frame: frame)\n        sut.imageView.image = initialImage\n        sut.imageView.image = updatedImage\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.imageView, \"object's elements should be initialized\")\n        XCTAssertEqual (sut.imageView.image, updatedImage, \"object's imageView image should update\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploaderWidgetPreviewTests/UploaderWidgetPreviewViewControllerTests.swift",
    "content": "//\n//  UploaderWidgetPreviewViewControllerTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport Foundation\nimport XCTest\n\nclass UploaderWidgetPreviewViewControllerTests: WidgetBaseTest, CLDWidgetPreviewDelegate {\n    \n    var sut: CLDWidgetPreviewViewController!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - delegate\n    func widgetPreviewViewController(_ controller: CLDWidgetPreviewViewController, didFinishEditing assets: [CLDWidgetAssetContainer]) {}\n    func widgetPreviewViewController(_ controller: CLDWidgetPreviewViewController, didSelect asset: CLDWidgetAssetContainer) {}\n    func widgetPreviewViewControllerDidCancel(_ controller: CLDWidgetPreviewViewController) {}\n    \n    // MARK: - test init\n    func test_init_emptyArray_shouldCreateObject() {\n        \n        // Given\n        let assets: [CLDWidgetAssetContainer] = []\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assets)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n    }\n    func test_init_emptyDelegate_shouldCreateObject() {\n        \n        // Given\n        let assets = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assets, delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n    }\n    func test_init_mixAssetsAndDelegate_shouldCreateObjectWithProperties() {\n        \n        // Given\n        let assetContainers = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assetContainers, delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"delegate should be initialized\")\n        XCTAssertEqual (sut.assets, assetContainers, \"objects should be equal\")\n        XCTAssertEqual (sut.selectedIndex, 0, \"selectedIndex should be created with default value of 0\")\n    }\n    func test_init_imageAssetsAndDelegate_shouldCreateObjectWithProperties() {\n        \n        // Given\n        let assetContainers = createImageOnlyAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assetContainers, delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"delegate should be initialized\")\n        XCTAssertEqual (sut.assets, assetContainers, \"objects should be equal\")\n        XCTAssertEqual (sut.selectedIndex, 0, \"selectedIndex should be created with default value of 0\")\n    }\n    func test_init_videoAssetsAndDelegate_shouldCreateObjectWithProperties() {\n        \n        // Given\n        let assetContainers = createVideoOnlyAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assetContainers, delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"delegate should be initialized\")\n        XCTAssertEqual (sut.assets, assetContainers, \"objects should be equal\")\n        XCTAssertEqual (sut.selectedIndex, 0, \"selectedIndex should be created with default value of 0\")\n    }\n    func test_init_delegateAfterInit_shouldCreateObjectWithDelegate() {\n        \n        // Given\n        let assetContainers = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assetContainers, delegate: nil)\n        sut.delegate = self\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"delegate should be initialized\")\n    }\n    func test_createView_shouldCreateObjectWithUIElements() {\n        \n        // Given\n        let assetContainers = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assetContainers, delegate: self)\n        let _ = sut.view\n           \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.collectionView, \"object should be initialized\")\n        XCTAssertNotNil(sut.mainImageView, \"object should be initialized\")\n        XCTAssertNotNil(sut.videoView, \"object should be initialized\")\n        XCTAssertNotNil(sut.uploadButton, \"object should be initialized\")\n    }\n    func test_initWithAssetsAndCreateView_shouldCreateCollectionWithSpecificCellCount() {\n        \n        // Given\n        let assetContainers = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assetContainers, delegate: self)\n        let _ = sut.view\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"object should be initialized\")\n        XCTAssertEqual (sut.collectionView.numberOfItems(inSection: 0),assetContainers.count, \"objects should be equal\")\n    }\n    func test_initWithMixAssetsAndCreateView_shouldCreateImageViewWithSpecificImage() {\n        \n        // Given\n        let assetContainers = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assetContainers, delegate: self)\n        let _ = sut.view\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"object should be initialized\")\n        XCTAssertEqual (sut.mainImageView.image, assetContainers[0].presentationImage, \"objects should be equal\")\n    }\n    func test_initWithImageAssetsAndCreateView_shouldCreateImageViewWithSpecificImage() {\n        \n        // Given\n        let assetContainers = createImageOnlyAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assetContainers, delegate: self)\n        let _ = sut.view\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"object should be initialized\")\n        XCTAssertEqual (sut.mainImageView.image, assetContainers[0].presentationImage, \"objects should be equal\")\n    }\n    func test_initWithVideoAssetsAndCreateView_shouldCreateImageViewWithSpecificImage() {\n        \n        // Given\n        let assetContainers = createVideoOnlyAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assetContainers, delegate: self)\n        let _ = sut.view\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"object should be initialized\")\n        XCTAssertEqual (sut.videoView.player.currentItem, assetContainers[0].originalVideo, \"objects should be equal\")\n    }\n    func test_initWithAssetsAndCreateView_shouldCreateUploadButtonWithSpecificType() {\n        \n        // Given\n        let assetContainers = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetPreviewViewController(assets: assetContainers, delegate: self)\n        let _ = sut.view\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"object should be initialized\")\n        XCTAssertEqual (sut.uploadButton.buttonType, .custom, \"objects should be equal\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploaderWidgetTests/UploaderWidgetTests.m",
    "content": "//\n//  ObjcUploaderWidgetTests.m\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n#import <XCTest/XCTest.h>\n#import <Cloudinary/Cloudinary-Swift.h>\n#import \"NetworkBaseTestObjc.h\"\n#import <AVKit/AVKit.h>\n\n@interface ObjcUploaderWidgetTests : NetworkBaseTestObjc <CLDUploaderWidgetDelegate>\n@property (nonatomic, strong, nullable) CLDUploaderWidget* sut;\n@end\n\n@implementation ObjcUploaderWidgetTests\n\n// MARK: - setup and teardown\n- (void)setUp {\n    [super setUp];\n}\n- (void)tearDown {\n    [super tearDown];\n    self.sut = nil;\n}\n\n// MARK: - helper methods\n- (NSArray<UIImage*>*)createImagesArray {\n   \n    NSMutableArray* imagesArray = [NSMutableArray new];\n    \n    for (int index = 0; index < 10; index++) {\n        UIImage* image = [self getImageBy:logo];\n        [imagesArray addObject:image];\n    }\n    \n    return [NSArray arrayWithArray:imagesArray];\n}\n- (NSArray<AVPlayerItem*>*)createVideosArray {\n   \n    NSMutableArray* videosArray = [NSMutableArray new];\n    \n    for (int index = 0; index < 10; index++) {\n        AVPlayerItem* video = [self getVideoBy:dog];\n        [videosArray addObject:video];\n    }\n    \n    return [NSArray arrayWithArray:videosArray];\n}\n\n// MARK: - delegate\n- (void)uploadWidget:(CLDUploaderWidget * _Nonnull)widget willCall:(NSArray<CLDUploadRequest *> * _Nonnull)uploadRequests {}\n- (void)uploadWidgetDidDismiss {}\n- (void)widgetDidCancel:(CLDUploaderWidget * _Nonnull)widget {}\n\n// MARK: - test init\n- (void)test_init_cloudinary_shouldCreateObject {\n      \n    // Given\n    CLDCloudinary* cloudinaryObject = self.cloudinary;\n    \n    // When\n    self.sut = [[CLDUploaderWidget alloc] initWithCloudinary:cloudinaryObject configuration:nil images:nil videos:nil delegate:nil];\n\n    // Then\n    XCTAssertNotNil(self.sut, \"object should be initialized\");\n    XCTAssertEqual (self.sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\");\n}\n- (void)test_init_cloudinaryConfiguration_shouldCreateObject {\n      \n    // Given\n    CLDCloudinary* cloudinaryObject       = self.cloudinary;\n    CLDUploadType* uploadType             = [[CLDUploadType alloc] initWithSigned:true preset:nil];\n    CLDWidgetConfiguration* configuration = [[CLDWidgetConfiguration alloc] initWithAllowRotate:true initialAspectLockState:AspectRatioLockStateEnabledAndOff uploadType:uploadType];\n    \n    // When\n    self.sut = [[CLDUploaderWidget alloc] initWithCloudinary:cloudinaryObject configuration:configuration images:nil videos:nil delegate:nil];\n    \n    // Then\n    XCTAssertNotNil(self.sut, \"object should be initialized\");\n    XCTAssertEqual (self.sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\");\n    XCTAssertEqual (self.sut.configuration, configuration, \"objects should be equal\");\n}\n- (void)test_init_cloudinaryConfigurationImages_shouldCreateObject {\n      \n    // Given\n    CLDCloudinary* cloudinaryObject       = self.cloudinary;\n    NSArray* images                       = [self createImagesArray];\n    CLDUploadType* uploadType             = [[CLDUploadType alloc] initWithSigned:true preset:nil];\n    CLDWidgetConfiguration* configuration = [[CLDWidgetConfiguration alloc] initWithAllowRotate:true initialAspectLockState:AspectRatioLockStateEnabledAndOff uploadType:uploadType];\n    \n    // When\n    self.sut = [[CLDUploaderWidget alloc] initWithCloudinary:cloudinaryObject configuration:configuration images:images videos:nil delegate:nil];\n    \n    // Then\n    XCTAssertNotNil(self.sut, \"object should be initialized\");\n    XCTAssertEqual (self.sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\");\n    XCTAssertEqual (self.sut.configuration, configuration, \"objects should be equal\");\n    XCTAssertEqual (self.sut.images, images, \"objects should be equal\");\n}\n- (void)test_convenienceInit_cloudinaryConfigurationImages_shouldCreateObject {\n      \n    // Given\n    CLDCloudinary* cloudinaryObject       = self.cloudinary;\n    NSArray* images                       = [self createImagesArray];\n    CLDUploadType* uploadType             = [[CLDUploadType alloc] initWithSigned:true preset:nil];\n    CLDWidgetConfiguration* configuration = [[CLDWidgetConfiguration alloc] initWithAllowRotate:true initialAspectLockState:AspectRatioLockStateEnabledAndOff uploadType:uploadType];\n    \n    // When\n    self.sut = [[CLDUploaderWidget alloc] initWithCloudinary:cloudinaryObject configuration:configuration images:images delegate:nil];\n    \n    // Then\n    XCTAssertNotNil(self.sut, \"object should be initialized\");\n    XCTAssertEqual (self.sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\");\n    XCTAssertEqual (self.sut.configuration, configuration, \"objects should be equal\");\n    XCTAssertEqual (self.sut.images, images, \"objects should be equal\");\n}\n- (void)test_init_cloudinaryConfigurationImagesVideos_shouldCreateObject {\n      \n    // Given\n    CLDCloudinary* cloudinaryObject       = self.cloudinary;\n    NSArray* images                       = [self createImagesArray];\n    NSArray* videos                       = [self createVideosArray];\n    CLDUploadType* uploadType             = [[CLDUploadType alloc] initWithSigned:true preset:nil];\n    CLDWidgetConfiguration* configuration = [[CLDWidgetConfiguration alloc] initWithAllowRotate:true initialAspectLockState:AspectRatioLockStateEnabledAndOff uploadType:uploadType];\n    \n    // When\n    self.sut = [[CLDUploaderWidget alloc] initWithCloudinary:cloudinaryObject configuration:configuration images:images videos:videos delegate:nil];\n    \n    // Then\n    XCTAssertNotNil(self.sut, \"object should be initialized\");\n    XCTAssertEqual (self.sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\");\n    XCTAssertEqual (self.sut.configuration, configuration, \"objects should be equal\");\n    XCTAssertEqual (self.sut.images, images, \"objects should be equal\");\n    XCTAssertEqual (self.sut.videos, videos, \"objects should be equal\");\n}\n- (void)test_init_allProperties_shouldCreateObject {\n      \n    // Given\n    CLDCloudinary* cloudinaryObject       = self.cloudinary;\n    NSArray* images                       = [self createImagesArray];\n    NSArray* videos                       = [self createVideosArray];\n    CLDUploadType* uploadType             = [[CLDUploadType alloc] initWithSigned:true preset:nil];\n    CLDWidgetConfiguration* configuration = [[CLDWidgetConfiguration alloc] initWithAllowRotate:true initialAspectLockState:AspectRatioLockStateEnabledAndOff uploadType:uploadType];\n    \n    // When\n    self.sut = [[CLDUploaderWidget alloc] initWithCloudinary:cloudinaryObject configuration:configuration images:images videos:videos delegate:self];\n    \n    // Then\n    XCTAssertNotNil(self.sut, \"object should be initialized\");\n    XCTAssertNotNil(self.sut.delegate, \"object should be initialized\");\n    XCTAssertEqual (self.sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\");\n    XCTAssertEqual (self.sut.configuration, configuration, \"objects should be equal\");\n    XCTAssertEqual (self.sut.images, images, \"objects should be equal\");\n    XCTAssertEqual (self.sut.videos, videos, \"objects should be equal\");\n}\n\n// MARK: - test update\n- (void)test_update_allProperties_shouldCreateObject {\n      \n    // Given\n    CLDCloudinary* initialCloudinaryObject = self.cloudinary;\n    CLDCloudinary* updatedCloudinaryObject = self.cloudinary;\n    NSArray* images                        = [self createImagesArray];\n    NSArray* videos                        = [self createVideosArray];\n    CLDUploadType* uploadType              = [[CLDUploadType alloc] initWithSigned:true preset:nil];\n    CLDWidgetConfiguration* configuration  = [[CLDWidgetConfiguration alloc] initWithAllowRotate:true initialAspectLockState:AspectRatioLockStateEnabledAndOff uploadType:uploadType];\n    \n    // When\n    self.sut = [[CLDUploaderWidget alloc] initWithCloudinary:initialCloudinaryObject configuration:nil images:nil videos:nil delegate:nil];\n    [[[[[self.sut setCloudinaryFromCloudinary:updatedCloudinaryObject] setConfigurationFromConfiguration:configuration] setImagesFromImages:images] setVideosFromVideoItems:videos] setDelegate:self];\n    \n    // Then\n    XCTAssertNotNil(self.sut, \"object should be initialized\");\n    XCTAssertNotNil(self.sut.delegate, \"object should be initialized\");\n    XCTAssertEqual (self.sut.cloudinaryObject, updatedCloudinaryObject, \"objects should be equal\");\n    XCTAssertEqual (self.sut.configuration, configuration, \"objects should be equal\");\n    XCTAssertEqual (self.sut.videos, videos, \"objects should be equal\");\n}\n\n@end\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploaderWidgetTests/UploaderWidgetTests.swift",
    "content": "//\n//  UploaderWidgetTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport XCTest\n@testable import Cloudinary\n\nclass UploaderWidgetTests: WidgetBaseTest, CLDUploaderWidgetDelegate {\n\n    var sut: CLDUploaderWidget!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - delegate\n    func uploadWidget(_ widget: CLDUploaderWidget, willCall uploadRequests: [CLDUploadRequest]) {}\n    func widgetDidCancel(_ widget: CLDUploaderWidget) {}\n    func uploadWidgetDidDismiss() {}\n    \n    // MARK: - test init\n    func test_init_cloudinary_shouldCreateObject() {\n        \n        // Given\n        let cloudinaryObject = cloudinary!\n        \n        // When\n        sut = CLDUploaderWidget(cloudinary: cloudinaryObject, configuration: nil, images: nil, videos: nil, delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertEqual (sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\")\n        \n    }\n    func test_init_cloudinaryConfiguration_shouldCreateObject() {\n        \n        // Given\n        let cloudinaryObject = cloudinary!\n        let configuration    = CLDWidgetConfiguration()\n        \n        // When\n        sut = CLDUploaderWidget(cloudinary: cloudinaryObject, configuration: configuration, images: nil, videos: nil, delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertEqual (sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n    }\n    func test_init_cloudinaryConfigurationImages_shouldCreateObject() {\n        \n        // Given\n        let images           = createImages()\n        let cloudinaryObject = cloudinary!\n        let configuration    = CLDWidgetConfiguration()\n        \n        // When\n        sut = CLDUploaderWidget(cloudinary: cloudinaryObject, configuration: configuration, images: images, videos: nil, delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertEqual (sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n        XCTAssertEqual (sut.images, images, \"objects should be equal\")\n    }\n    func test_convenienceInit_cloudinaryConfigurationImages_shouldCreateObject() {\n        \n        // Given\n        let images           = createImages()\n        let cloudinaryObject = cloudinary!\n        let configuration    = CLDWidgetConfiguration()\n        \n        // When\n        sut = CLDUploaderWidget(cloudinary: cloudinaryObject, configuration: configuration, images: images, delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertEqual (sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n        XCTAssertEqual (sut.images, images, \"objects should be equal\")\n    }\n    func test_init_cloudinaryConfigurationImagesVideos_shouldCreateObject() {\n        \n        // Given\n        let images           = createImages()\n        let videos           = createVideos()\n        let cloudinaryObject = cloudinary!\n        let configuration    = CLDWidgetConfiguration()\n        \n        // When\n        sut = CLDUploaderWidget(cloudinary: cloudinaryObject, configuration: configuration, images: images, videos: videos, delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertEqual (sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n        XCTAssertEqual (sut.images, images, \"objects should be equal\")\n        XCTAssertEqual (sut.videos, videos, \"objects should be equal\")\n    }\n    func test_init_allProperties_shouldCreateObject() {\n        \n        // Given\n        let images           = createImages()\n        let videos           = createVideos()\n        let cloudinaryObject = cloudinary!\n        let configuration    = CLDWidgetConfiguration()\n        \n        // When\n        sut = CLDUploaderWidget(cloudinary: cloudinaryObject, configuration: configuration, images: images, videos: videos, delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"object should be set\")\n        XCTAssertEqual (sut.cloudinaryObject, cloudinaryObject, \"objects should be equal\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n        XCTAssertEqual (sut.images, images, \"objects should be equal\")\n        XCTAssertEqual (sut.videos, videos, \"objects should be equal\")\n    }\n    \n    // MARK: - update\n    func test_update_allProperties_shouldCreateObject() {\n        \n        // Given\n        let images                  = createImages()\n        let videos                  = createVideos()\n        let initialCloudinaryObject = cloudinary!\n        let updatedCloudinaryObject = cloudinarySecured!\n        let configuration           = CLDWidgetConfiguration()\n        \n        // When\n        sut = CLDUploaderWidget(cloudinary: initialCloudinaryObject, configuration: nil, images: nil, videos: nil, delegate: nil)\n        sut.setCloudinary(updatedCloudinaryObject).setConfiguration(configuration).setImages(images).setVideos(videos).setDelegate(self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"object should be set\")\n        XCTAssertEqual (sut.cloudinaryObject, updatedCloudinaryObject, \"objects should be equal\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n        XCTAssertEqual (sut.images, images, \"objects should be equal\")\n        XCTAssertEqual (sut.videos, videos, \"objects should be equal\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/UploaderWidgetViewControllerTests/UploaderWidgetViewControllerTests.swift",
    "content": "//\n//  UploaderWidgetViewControllerTests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport Foundation\nimport XCTest\n@testable import Cloudinary\n\nclass UploaderWidgetViewControllerTests: WidgetBaseTest, CLDWidgetViewControllerDelegate {\n    \n    var sut: CLDWidgetViewController!\n    \n    // MARK: - setup and teardown\n    override func setUp() {\n        super.setUp()\n    }\n    override func tearDown() {\n        sut = nil\n        super.tearDown()\n    }\n    \n    // MARK: - delegate\n    func widgetViewController(_ controller: CLDWidgetViewController, didFinishEditing editedAssets: [CLDWidgetAssetContainer]) { print(\"didFinishEditing\") }\n    func widgetViewControllerDidCancel(_ controller: CLDWidgetViewController) { print(\"did cancel\") }\n    \n    // MARK: - test init\n    func test_init_emptyArray_shouldCreateObject() {\n        \n        // Given\n        let assets: [CLDWidgetAssetContainer] = []\n        \n        // When\n        sut = CLDWidgetViewController(assets: assets)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n    }\n    func test_init_emptyDelegate_shouldCreateObject() {\n        \n        // Given\n        let assets = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetViewController(assets: assets, delegate: nil)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n    }\n    func test_init_mixAssetsAllProperties_shouldCreateObjectWithProperties() {\n        \n        // Given\n        let assets = createMixAssetContainers()\n        let configuration = CLDWidgetConfiguration(allowRotate: true, initialAspectLockState: .enabledAndOn)\n        \n        // When\n        sut = CLDWidgetViewController(assets: assets, configuration: configuration, delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"delegate should be initialized\")\n        XCTAssertEqual (sut.assets, assets, \"objects should be equal\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n    }\n    func test_init_imageAssetsAllProperties_shouldCreateObjectWithProperties() {\n        \n        // Given\n        let assets = createImageOnlyAssetContainers()\n        let configuration = CLDWidgetConfiguration(allowRotate: true, initialAspectLockState: .enabledAndOn)\n        \n        // When\n        sut = CLDWidgetViewController(assets: assets, configuration: configuration, delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"delegate should be initialized\")\n        XCTAssertEqual (sut.assets, assets, \"objects should be equal\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n    }\n    func test_init_videoAssetsAllProperties_shouldCreateObjectWithProperties() {\n        \n        // Given\n        let assets = createVideoOnlyAssetContainers()\n        let configuration = CLDWidgetConfiguration(allowRotate: true, initialAspectLockState: .enabledAndOn)\n        \n        // When\n        sut = CLDWidgetViewController(assets: assets, configuration: configuration, delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"delegate should be initialized\")\n        XCTAssertEqual (sut.assets, assets, \"objects should be equal\")\n        XCTAssertEqual (sut.configuration, configuration, \"objects should be equal\")\n    }\n    func test_init_updateAfterInit_shouldCreateObjectWithDelegate() {\n        \n        // Given\n        let assets = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetViewController(assets: assets, delegate: nil)\n        sut.delegate = self\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"delegate should be initialized\")\n    }\n    func test_createView_shouldCreateObjectWithUIElements() {\n        \n        // Given\n        let assets = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetViewController(assets: assets, delegate: self)\n        let _ = sut.view\n           \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.topButtonsView, \"object should be initialized\")\n        XCTAssertNotNil(sut.backButton, \"object should be initialized\")\n        XCTAssertNotNil(sut.actionButton, \"object should be initialized\")\n        XCTAssertNotNil(sut.containerView, \"object should be initialized\")\n    }\n    func test_initAndCreateView_shouldCreateTopButtonsWithSpecificType() {\n        \n        // Given\n        let assets = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetViewController(assets: assets, delegate: self)\n        let _ = sut.view\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.delegate, \"object should be initialized\")\n        XCTAssertEqual (sut.backButton.buttonType, .custom, \"objects should be equal\")\n        XCTAssertEqual (sut.actionButton.buttonType, .custom, \"objects should be equal\")\n    }\n    func test_init_shouldCreatePreviewViewController() {\n        \n        // Given\n        let assets = createMixAssetContainers()\n        \n        // When\n        sut = CLDWidgetViewController(assets: assets, delegate: self)\n        \n        // Then\n        XCTAssertNotNil(sut, \"object should be initialized\")\n        XCTAssertNotNil(sut.previewViewController, \"object should be initialized\")\n    }\n}\n"
  },
  {
    "path": "Example/Tests/UploadWidgetTests/WidgetBaseTest.swift",
    "content": "//\n//  WidgetBaseTest.swift\n//\n//  Copyright (c) 2016 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\n@testable import Cloudinary\nimport AVKit\n\nclass WidgetBaseTest: NetworkBaseTest {\n        \n    func createMixAssetContainers() -> [CLDWidgetAssetContainer] {\n        \n        var assetContainers = [CLDWidgetAssetContainer]()\n        \n        for _ in 1...10 {\n            let imageContainer = CLDWidgetAssetContainer(originalImage: getImage(.logo), editedImage: getImage(.logo))\n            assetContainers.append(imageContainer)\n        }\n        \n        for _ in 1...10 {\n            let videoContainer = CLDWidgetAssetContainer.init(videoItem: getVideo(.dog))\n            assetContainers.append(videoContainer)\n        }\n        \n        return assetContainers\n    }\n    \n    func createImageOnlyAssetContainers() -> [CLDWidgetAssetContainer] {\n        \n        var assetContainers = [CLDWidgetAssetContainer]()\n        \n        for _ in 1...10 {\n            let imageContainer = CLDWidgetAssetContainer(originalImage: getImage(.logo), editedImage: getImage(.logo))\n            assetContainers.append(imageContainer)\n        }\n        \n        return assetContainers\n    }\n    \n    func createVideoOnlyAssetContainers() -> [CLDWidgetAssetContainer] {\n        \n        var assetContainers = [CLDWidgetAssetContainer]()\n        \n        for _ in 1...10 {\n            let videoContainer = CLDWidgetAssetContainer.init(videoItem: getVideo(.dog))\n            assetContainers.append(videoContainer)\n        }\n        \n        return assetContainers\n    }\n    \n    func createImages() -> [UIImage] {\n        \n        var images = [UIImage]()\n        \n        for _ in 1...10 {\n            let image = getImage(.logo)\n            images.append(image)\n        }\n        \n        return images\n    }\n    \n    func createVideos() -> [AVPlayerItem] {\n        \n        var videos = [AVPlayerItem]()\n        \n        for _ in 1...10 {\n            let video = getVideo(.dog)\n            videos.append(video)\n        }\n        \n        return videos\n    }\n}\n\n"
  },
  {
    "path": "Example/WidgetUITests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Example/WidgetUITests/WidgetUITests.swift",
    "content": "//\n//  WidgetUITests.swift\n//\n//  Copyright (c) 2020 Cloudinary (http://cloudinary.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 all\n//  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 THE\n//  SOFTWARE.\n//\n\nimport XCTest\n\nclass WidgetUITests: XCTestCase {\n\n    var app: XCUIApplication!\n    \n    override func setUpWithError() throws {\n        \n        try super.setUpWithError()\n        \n        app = XCUIApplication()\n        app.launch()\n        \n        continueAfterFailure = false\n    }\n\n    override func tearDownWithError() throws {\n        \n        try super.tearDownWithError()\n        \n        app = nil\n    }\n\n    // MARK: - rotate button\n    func test_rotateStates_on_shouldShowRotateButton() {\n             \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        app.buttons[UITestConstants.widgetViewControllerActionButton].tap()\n        \n        let rotateButton = app.buttons[UITestConstants.editViewControllerRotateButton]\n        \n        // Then\n        XCTAssertTrue(rotateButton.exists, \"button should exist\")\n        XCTAssertTrue(rotateButton.isEnabled, \"button should be enabled\")\n    }\n    func test_rotateStates_off_shouldNotShowRotateButton() {\n           \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.switches[UITestConstants.rotateStateSwitch].swipeLeft()\n        \n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        app.buttons[UITestConstants.widgetViewControllerActionButton].tap()\n        \n        let rotateButton = app.buttons[UITestConstants.editViewControllerRotateButton]\n        \n        // Then\n        XCTAssertFalse(rotateButton.exists, \"button should not exist\")\n    }\n    \n    // MARK: - action button\n    func test_actionButtonStates_noVideoEnabledAndOff_shouldShowActionButtonWithText() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        let actionButton = app.buttons[UITestConstants.widgetViewControllerActionButton]\n        actionButton.tap()\n        \n        // Then\n        XCTAssertTrue (actionButton.exists, \"button should exist\")\n        XCTAssertTrue (actionButton.isEnabled, \"button should be enabled\")\n        XCTAssertEqual(actionButton.label, \"Aspect ratio unlocked \", \"button label should be set to string\")\n    }\n    func test_actionButtonStates_noVideoEnabledAndOn_shouldShowActionButtonWithText() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.aspectLockSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        let actionButton = app.buttons[UITestConstants.widgetViewControllerActionButton]\n        actionButton.tap()\n        \n        // Then\n        XCTAssertTrue (actionButton.exists, \"button should exist\")\n        XCTAssertTrue (actionButton.isEnabled, \"button should be enabled\")\n        XCTAssertEqual(actionButton.label, \"Aspect ratio locked \", \"button label should be set to string\")\n    }\n    func test_actionButtonStates_noVideoDisabled_shouldHideActionButton() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.aspectLockSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        app.buttons[UITestConstants.widgetViewControllerActionButton].tap()\n        let actionButton = app.buttons[UITestConstants.widgetViewControllerActionButton]\n        \n        // Then\n        XCTAssertTrue (actionButton.exists, \"button should exist\")\n        XCTAssertFalse(actionButton.isEnabled, \"button should be disabled\")\n        XCTAssertEqual(actionButton.label, String(), \"button label should be set to empty string\")\n    }\n    func test_actionButtonStates_withVideoEnabledAndOff_shouldShowActionButtonWithText() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        let actionButton = app.buttons[UITestConstants.widgetViewControllerActionButton]\n        actionButton.tap()\n        \n        // Then\n        XCTAssertTrue (actionButton.exists, \"button should exist\")\n        XCTAssertFalse(actionButton.isEnabled, \"button should be disabled\")\n        XCTAssertEqual(actionButton.label, String(), \"button label should be set to empty string\")\n    }\n    func test_actionButtonStates_withVideoEnabledAndOn_shouldShowActionButtonWithText() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.aspectLockSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        let actionButton = app.buttons[UITestConstants.widgetViewControllerActionButton]\n        actionButton.tap()\n        \n        // Then\n        XCTAssertTrue (actionButton.exists, \"button should exist\")\n        XCTAssertFalse(actionButton.isEnabled, \"button should be disabled\")\n        XCTAssertEqual(actionButton.label, String(), \"button label should be set to empty string\")\n    }\n    func test_actionButtonStates_withVideoDisabled_shouldHideActionButton() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.aspectLockSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        app.buttons[UITestConstants.widgetViewControllerActionButton].tap()\n        let actionButton = app.buttons[UITestConstants.widgetViewControllerActionButton]\n        \n        // Then\n        XCTAssertTrue (actionButton.exists, \"button should exist\")\n        XCTAssertFalse(actionButton.isEnabled, \"button should be disabled\")\n        XCTAssertEqual(actionButton.label, String(), \"button label should be set to empty string\")\n    }\n    \n    // MARK: - collection view\n    func test_collectionView_many_shouldHaveManyCells() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        let secondCell = app.collectionViews.children(matching: .cell).element(boundBy: 1)\n        \n        // Then\n        XCTAssertTrue(secondCell.exists, \"second cell should exist\")\n    }\n    func test_collectionView_oneImage_shouldHaveOneCell() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        let firstCell = app.collectionViews.children(matching: .cell).element(boundBy: 0)\n        let secondCell = app.collectionViews.children(matching: .cell).element(boundBy: 1)\n        \n        // Then\n        XCTAssertTrue(firstCell.exists, \"one cell should exist\")\n        XCTAssertFalse(secondCell.exists, \"only one cell should exist\")\n    }\n    func test_collectionView_oneVideo_shouldHaveOneCell() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        let firstCell = app.collectionViews.children(matching: .cell).element(boundBy: 0)\n        let secondCell = app.collectionViews.children(matching: .cell).element(boundBy: 1)\n        \n        // Then\n        XCTAssertTrue(firstCell.exists, \"one cell should exist\")\n        XCTAssertFalse(secondCell.exists, \"only one cell should exist\")\n    }\n    func test_collectionView_none_shouldPresentImagePicker() {\n        \n        // Given\n        let existsPredicate = NSPredicate(format: \"exists == true\")\n       \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        let imagePicker = app.navigationBars[UITestConstants.photos]\n        \n        // wait for image picker to load\n        expectation(for: existsPredicate, evaluatedWith: imagePicker, handler: nil)\n        waitForExpectations(timeout: 15, handler: nil)\n        \n        // Then\n        XCTAssertTrue(imagePicker.exists, \"if no assets added to the widget, image picker should be presented\")\n    }\n    \n    // MARK: - video view\n    func test_videoView_oneVideo_shouldBePresented() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        let isHittable = app.otherElements[UITestConstants.previewViewControllerVideoView].isHittable\n        \n        // Then\n        XCTAssertTrue(isHittable, \"video view should be presented when video is selected\")\n    }\n    func test_videoView_mixAssets_shouldBePresented() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 0).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 0).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        let isHittable = app.otherElements[UITestConstants.previewViewControllerVideoView].isHittable\n        \n        // Then\n        XCTAssertTrue(isHittable, \"video view should be presented when video is selected\")\n    }\n    func test_videoView_noVideo_shouldNotBePresented() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        let presented = app.otherElements[UITestConstants.previewViewControllerVideoView].exists\n        \n        // Then\n        XCTAssertFalse(presented, \"video view should not be presented when video is not selected\")\n    }\n    \n    // MARK: - video controls view\n    func test_videoControlView_oneVideo_shouldExist() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        let videoControlExists = app.otherElements[UITestConstants.videoControlsView].exists\n        \n        // Then\n        XCTAssertTrue(videoControlExists, \"video control should exist in this situation\")\n    }\n    func test_videoControlViewButton_oneVideo_shouldBeHittble() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        let isHittable = app.buttons[UITestConstants.videoViewPausePlayButton].isHittable\n        \n        // Then\n        XCTAssertTrue(isHittable, \"pausePlayButton should be presented when video is selected\")\n    }\n    func test_videoControlViewButton_oneVideo_shouldUpdateTextOnPress() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        let initialButtonText = app.buttons[UITestConstants.videoViewPausePlayButton].label\n        app.buttons[UITestConstants.videoViewPausePlayButton].tap()\n        let updatedButtonText = app.buttons[UITestConstants.videoViewPausePlayButton].label\n        \n        // Then\n        XCTAssertNotEqual(initialButtonText, updatedButtonText, \"pressing pausePlayButton should change its state and text\")\n    }\n    func test_videoControlViewTimer_oneVideo_videoControlViewShouldDisappearAfterShortTime() {\n        \n        // Given\n        let hittablePredicate = NSPredicate(format: \"isHittable == false\")\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        let pausePlayButton = app.buttons[UITestConstants.videoViewPausePlayButton]\n        \n        // wait for pausePlayButton to disappear\n        expectation(for: hittablePredicate, evaluatedWith: pausePlayButton, handler: nil)\n        waitForExpectations(timeout: 10, handler: nil)\n        \n        // Then\n        XCTAssertFalse(pausePlayButton.exists, \"playPauseButton should disappear after a few seconds when the video is playing and showing the controls\")\n    }\n    func test_videoControlView_backgroundPressed_videoControlViewShouldDisappear() {\n                \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n       \n        // tap() will tap in the middle (on the button!) this code will force background press\n        let videoControls = app.otherElements[UITestConstants.videoControlsView]\n        let normalized = videoControls.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0))\n        let coordinate = normalized.withOffset(CGVector(dx: 10, dy: 10))\n        coordinate.tap()\n        \n        let pausePlayButton = app.buttons[UITestConstants.videoViewPausePlayButton]\n        \n        // Then\n        XCTAssertFalse(pausePlayButton.exists, \"playPauseButton should disappear after a few seconds when the video is playing and showing the controls\")\n    }\n    \n    // MARK: - video player view\n    func test_videoPlayerView_oneVideo_shouldExist() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 2).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        let videoPlayerExists = app.otherElements[UITestConstants.videoPlayerView].exists\n        \n        // Then\n        XCTAssertTrue(videoPlayerExists, \"video player should exist when video view is presented\")\n    }\n    \n    // MARK: - image video transitions\n    func test_imageVideoTransitions_videoToImage_shouldNotPresentVideoView() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        app.collectionViews.children(matching: .cell).element(boundBy: 1).tap()\n        \n        let presented = app.otherElements[UITestConstants.previewViewControllerVideoView].exists\n        \n        // Then\n        XCTAssertFalse(presented, \"video view should not be presented when video is not selected\")\n    }\n    func test_imageVideoTransitions_videoToImageToVideo_shouldPresentVideoView() {\n        \n        // When\n        app.buttons[UITestConstants.goToWidgetBarButton].tap()\n        app.segmentedControls[UITestConstants.initialImagesSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.segmentedControls[UITestConstants.initialVideosSegmented].children(matching: .button).element(boundBy: 1).tap()\n        app.buttons[UITestConstants.widgetSettingsPresentBarButton].tap()\n        \n        app.collectionViews.children(matching: .cell).element(boundBy: 1).tap()\n        app.collectionViews.children(matching: .cell).element(boundBy: 0).tap()\n        \n        let presented = app.otherElements[UITestConstants.previewViewControllerVideoView].exists\n        \n        // Then\n        XCTAssertTrue(presented, \"video view should be presented when video is selected\")\n    }\n    \n}\n\nclass UITestConstants {\n    \n    static let goToWidgetBarButton              = \"goToWidgetBarButton\"\n    static let widgetSettingsPresentBarButton   = \"widgetSettingsPresentBarButton\"\n    static let widgetViewControllerActionButton = \"widgetViewControllerActionButton\"\n    static let editViewControllerRotateButton   = \"editViewControllerRotateButton\"\n    static let rotateStateSwitch                = \"rotateStateSwitch\"\n    static let aspectLockSegmented              = \"aspectLockSegmented\"\n    static let initialImagesSegmented           = \"initialImagesSegmented\"\n    static let initialVideosSegmented           = \"initialVideosSegmented\"\n    static let allPhotos                        = \"All Photos\"\n    static let photos                           = \"Photos\"\n    \n    static let previewViewControllerVideoView   = \"previewViewControllerVideoView\"\n    static let videoViewPausePlayButton         = \"videoViewPausePlayButton\"\n    static let videoControlsView                = \"videoControlsView\"\n    static let videoPlayerView                  = \"videoPlayerView\"\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2016 Cloudinary (http://cloudinary.com)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:5.1\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"Cloudinary\",\n    platforms: [ .iOS(.v9)],\n    products: [\n        // Products define the executables and libraries produced by a package, and make them visible to other packages.\n        .library(\n            name: \"Cloudinary\",\n            targets: [\"Cloudinary\"]),\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: \"Cloudinary\",\n            path: \"Cloudinary/Classes\"),\n    ]\n)\n"
  },
  {
    "path": "Package@swift-5.3.swift",
    "content": "// swift-tools-version:5.3\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"Cloudinary\",\n    platforms: [ .iOS(.v9)],\n    products: [\n        // Products define the executables and libraries produced by a package, and make them visible to other packages.\n        .library(\n            name: \"Cloudinary\",\n            targets: [\"Cloudinary\"]),\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: \"Cloudinary\",\n            path: \"Cloudinary/Classes\",\n            resources: [\n                .copy(\"Core/Network/PrivacyInfo.xcprivacy\")\n            ]\n        ),\n    ]\n)\n"
  },
  {
    "path": "README.md",
    "content": "Cloudinary iOS SDK\n=========================\n[![Build Status](https://api.travis-ci.com/cloudinary/cloudinary_ios.svg?branch=master)](https://app.travis-ci.com/github/cloudinary/cloudinary_ios)\n## About\nThe Cloudinary iOS SDK allows you to quickly and easily integrate your application with Cloudinary.\nEffortlessly optimize and transform your cloud's assets.\n\n### Additional documentation\nThis Readme provides basic installation and usage information.\nFor the complete documentation, see the [iOS SDK Guide](https://cloudinary.com/documentation/ios_integration).\n\n## Table of Contents\n- [Key Features](#key-features)\n- [Version Support](#Version-Support)\n- [Installation](#installation)\n- [Usage](#usage)\n    - [Setup](#Setup)\n    - [Transform and Optimize Assets](#Transform-and-Optimize-Assets)\n    - [File Upload](#File-Upload)\n    - [File Download](#File-Download)\n\n## Key Features\n- [Transform](https://cloudinary.com/documentation/ios_video_manipulation#video_transformation_examples) and [optimize](https://cloudinary.com/documentation/ios_image_manipulation#image_optimizations) assets.\n\n## Version Support\n| SDK Version    | iOS 9+    |   iOS 8   |\n|----------------|-----------|-----------|\n| 2.0.0 - 2.10.1 | V         | V         |\n| 3.0.0 - 5.x.x  | V         | X         |\n\n## Installation\n### CocoaPods\n\n[CocoaPods](http://cocoapods.org) is a dependency manager for Swift and Objective-C Cocoa projects. \nTo install CocoaPods:\n\n```bash\nsudo gem install cocoapods\n```\nIf you don't have a `Podfile` in your project yet, add it by running the command:\n```bash\npod init\n```\n\nAdd the Cloudinary SDK to your `Podfile`:\n\n```ruby\nsource 'https://github.com/CocoaPods/Specs.git'\nplatform :ios, '9.0'\nuse_frameworks!\n\ntarget 'MyApp' do\n  pod 'Cloudinary', '~> 5.0'\nend\n```\n\nThen, run the command:\n\n```bash\npod install\n```\n\n### Carthage\n\nCreate `Cartfile`\n```bash\ntouch Cartfile\n```\n\nOpen `Cartfile` and enter the following line\n\n```bash\ngithub \"cloudinary/cloudinary_ios\" ~> 5.0\n```\n\nThen, run the command:\n\n```bash\ncarthage update --use-xcframeworks\n```\nA `Cartfile.resolved` file and a `Carthage` directory will appear in the same directory where your `.xcodeproj` or `.xcworkspace` is.\nDrag the built `.xcframework` bundles from `Carthage/Build` into the `Frameworks and Libraries` section of your application’s Xcode project.\n\n### Swift Package Manager\n* File > Add Packages... >\n* Add https://github.com/cloudinary/cloudinary_ios.git\n* Select \"Up to Next Major\" with \"5.0.0\"\n\n### Working with the Cloudinary iOS SDK Manually\n\nIf you prefer not use a dependency manager, you can add Cloudinary manually by adding it as a submodule to your project:\n\nOpen Terminal and navigate to your project's top level directory.\n\nIf your project is not initialized as a git repository, run the command:\n\n```bash\ngit init\n```\n\nTo add cloudinary as a git submodule, run the command:\n\n```bash\ngit submodule add https://github.com/cloudinary/cloudinary_ios.git\n```\n\n#### Embedded Framework\n\n1. Drag `Cloudinary.xcodeproj` into the Project Navigator of your application's Xcode project. It should appear under your application's blue project icon.\n2. Select `Cloudinary.xcodeproj` and make sure the deployment target matches that of your application target.\n3. Select your application project. Under 'TARGETS' select your application, open the 'General' tab, click on the `+` button under the 'Embedded Binaries' and Select 'Cloudinary.framework'.\n\n## Usage \n### Setup\nTo use the API, you will need a CLDCloudinary instance, which is initialized with an instance of CLDConfiguration.\n\nThe CLDConfiguration must have its `cloudName` and `apiKey` properties set. Other properties are optional. \n\nSee [API, URLs and access identifiers](https://cloudinary.com/documentation/api_and_access_identifiers) for more details.\n\nThere are several ways to initialize CLDConfiguration. You can simply call its constructor with the desired params:\n```swift\nlet config = CLDConfiguration(cloudName: \"CLOUD_NAME\", apiKey: \"API_KEY\")\n```\n\nAnother way is by passing a URL of the form: cloudinary://API_KEY:API_SECRET@CLOUD_NAME\n```swift\nlet config = CLDConfiguration(cloudinaryUrl: \"cloudinary://<API_KEY>:<API_SECRET>@<CLOUD_NAME>\")\n```\n\nYou can also add the same URL as an environment parameters under `CLOUDINARY_URL`, then initialize CLDConfiguration using its static initializer\n```swift\nlet config = CLDConfiguration.initWithEnvParams()\n```\n\nNow you can create a CLDCloudinary instance to work with\n```swift\nlet cloudinary = CLDCloudinary(configuration: config)\n```\n\n### Transform and Optimize Assets\nThe following example generates a URL on an uploaded `sample` image:\n```swift\ncloudinary.createUrl().generate(\"sample.jpg\")\n\n// http://res.cloudinary.com/CLOUD_NAME/image/upload/sample.jpg\n```\n\nThe following example generates an image URL of an uploaded `sample` image while transforming it to fill a 100x150 rectangle:\n\n```swift\nlet transformation = CLDTransformation().setWidth(100).setHeight(150).setCrop(.crop)\ncloudinary.createUrl().setTransformation(transformation).generate(\"sample.jpg\")\n\n// http://res.cloudinary.com/CLOUD_NAME/image/upload/c_fill,h_150,w_100/sample.jpg\n```\n\nAnother example, embedding a smaller version of an uploaded image while generating a 90x90 face detection based thumbnail:\n\n```swift\nlet transformation = CLDTransformation().setWidth(90).setHeight(90).setCrop(.Thumb).setGravity(.Face)\ncloudinary.createUrl().setTransformation(transformation).generate(\"sample.jpg\")\n\n// http://res.cloudinary.com/CLOUD_NAME/image/upload/c_thumb,g_face,h_90,w_90/sample.jpg\n```\n\nYou can provide either a Facebook name or a numeric ID of a Facebook profile or a fan page.  \n\nEmbedding a Facebook profile to match your graphic design is very simple:\n\n```swift\nlet url = cloudinary.createUrl().setTransformation(CLDTransformation().setWidth(90).setHeight(130).setGravity(.Face).setCrop(.Fill)).setType(.Facebook).generate(\"billclinton.jpg\")\n\n// http://res.cloudinary.com/CLOUD_NAME/image/facebook/c_fill,g_face,h_130,w_90/billclinton.jpg\n```\n\nYou can also chain transformations together:\n\n```swift\nlet transformation = CLDTransformation().setWidth(100).setHeight(150).chain().setCrop(.Fit)\nlet url = cloudinary.createUrl().setTransformation().generate(\"sample.jpg\")\n\n// http://res.cloudinary.com/CLOUD_NAME/image/facebook/h_150,w_100/c_fit/sample.jpg\n```\n\n### File Upload\n\n##### 1. Signed upload\n\nUploading to your cloud is very straightforward.\n\nIn the following example the file located at `fileUrl` is uploaded to your cloud:\n\n```swift\ncloudinary.createUploader().upload(file: fileUrl)\n```\n\n`fileUrl` can point to either a local or a remote file.\n\nYou can also upload data:\n\n```swift\ncloudinary.createUploader().upload(data: data)\n```\n\nThe uploaded image is assigned a randomly generated public ID, which is returned as part of the response.\n\nYou can pass  an instance of `CLDUploadRequestParams` for extra parameters you'd want to pass as part of the upload request. For example, you can specify your own public ID instead of a randomly generated one.\n                                                                                                                             \nFor a full list of available upload parameters, see [the Upload API Reference](https://cloudinary.com/documentation/image_upload_api_reference#upload) documentation.\n\nYou can also pass a `progress` closure that is called periodically during the data transfer, and a `completionHandler` closure to be called once the request has finished, holding either the response object or the error.\n\n\nIn the following example, we apply an incoming transformation as part of the upload request, the transformation is applied before saving the image in the cloud.\nWe also specify a public ID and pass closures for the upload progress and completion handler.\n```swift\nlet params = CLDUploadRequestParams()\nparams.setTransformation(CLDTransformation().setGravity(.NorthWest))\nparams.setPublicId(\"my_public_id\")\nlet request = cloudinary.createUploader().upload(file: fileUrl, params: params, progress: { (bytes, totalBytes, totalBytesExpected) in\n    // Handle progress\n    }) { (response, error) in\n        // Handle response\n}\n```\n\n##### 2. Unsigned uploads using [Upload Presets.](https://cloudinary.com/documentation/ios_image_and_video_upload#unsigned_upload)\nYou can create an upload preset in your Cloudinary account console, defining rules that limit the formats, transformations, dimensions and more.\nOnce the preset is defined, it's name is supplied when calling upload. An upload call will only succeed if the preset name is used and the resource is within the preset's pre-defined limits.\n\nThe following example uploads a local resource, assuming a preset named 'sample_preset' already exists in the account:\n```swift\nlet request = cloudinary.createUploader().upload(url: file, uploadPreset: \"sample_preset\", params: CLDUploadRequestParams()).response({\n    (response, error) in\n    // Handle response\n})\n```\n\nEvery upload request returns a CLDUploadRequest instance, allowing options such as cancelling, suspending or resuming it.\n\n### File Download\n\nThe SDK provides some convenient methods for downloading files from your cloud:\n\n```swift\ncloudinary.createDownloader().fetchImage(url)\n```\n\nYou can also pass a `progress` closure that is called periodically during the data transfer, and a `completionHandler` closure to be called once the request has finished, holding either the fetched UIImage or an error.\n\n```swift\nlet request = cloudinary.createDownloader().fetchImage(url, progress: { (bytes, totalBytes, totalBytesExpected) in\n            // Handle progress\n            }) { (responseImage, error) in\n                // Handle response\n        }\n```\n\nEvery download request returns an instance implementing CLDNetworkDataRequest, allowing options such as cancelling, suspending or resuming it.\n\nThe downloaded image is cached both to the memory and the disk (customizable). The disk cache size is limited and can be changed.\n\n## Contributions\nSee [contributing guidelines](/CONTRIBUTING.md).\n\n## Get Help\nIf you run into an issue or have a question, you can either:\n- [Open a Github issue](https://github.com/cloudinary/cloudinary_ios/issues) (for issues related to the SDK)\n- [Open a support ticket](https://cloudinary.com/contact) (for issues related to your account)\n\n## About Cloudinary\nCloudinary is a powerful media API for websites and mobile apps alike, Cloudinary enables developers to efficiently manage, transform, optimize, and deliver images and videos through multiple CDNs. Ultimately, viewers enjoy responsive and personalized visual-media experiences—irrespective of the viewing device.\n\n## Additional Resources\n- [Cloudinary Transformation and REST API References](https://cloudinary.com/documentation/cloudinary_references): Comprehensive references, including syntax and examples for all SDKs.\n- [DevJams](https://www.youtube.com/playlist?list=PL8dVGjLA2oMr09amgERARsZyrOz_sPvqw): Cloudinary developer podcasts on YouTube.\n- [Cloudinary Academy](https://training.cloudinary.com/): Free self-paced courses, instructor-led virtual courses, and on-site courses.\n- [Code Explorers and Feature Demos](https://cloudinary.com/documentation/code_explorers_demos_index): A one-stop shop for all code explorers, Postman collections, and feature demos found in the docs.\n- [Cloudinary Roadmap](https://cloudinary.com/roadmap): Your chance to follow, vote, or suggest what Cloudinary should develop next.\n- [Cloudinary Facebook Community](https://www.facebook.com/groups/CloudinaryCommunity): Learn from and offer help to other Cloudinary developers.\n- [Cloudinary Account Registration](https://cloudinary.com/users/register/free): Free Cloudinary account registration.\n- [Cloudinary Website](https://cloudinary.com)\n\n## Licence\nReleased under the MIT license.\n"
  },
  {
    "path": "tools/get_test_cloud.sh",
    "content": "#!/usr/bin/env bash\n\nfunction test_cloud\n{\n   CLOUD_DETAILS=$(curl -X POST  \\-H 'Content-type:application/json' \\https://sub-account-testing.cloudinary.com/create_sub_account \\--data '{\"prefix\" : \"ios-test-cloud\"}')\n   \n   echo ${CLOUD_DETAILS} | python -c 'import json,sys;c=json.load(sys.stdin)[\"payload\"];print(\"cloudinary://%s:%s@%s\" % (c[\"cloudApiKey\"], c[\"cloudApiSecret\"], c[\"cloudName\"]))'\n}\n\ntest_cloud\n"
  }
]