├── Podfile ├── Podfile.lock ├── Pods ├── Alamofire │ ├── LICENSE │ ├── README.md │ └── Source │ │ ├── AFError.swift │ │ ├── Alamofire.swift │ │ ├── AlamofireExtended.swift │ │ ├── AuthenticationInterceptor.swift │ │ ├── CachedResponseHandler.swift │ │ ├── Combine.swift │ │ ├── DispatchQueue+Alamofire.swift │ │ ├── EventMonitor.swift │ │ ├── HTTPHeaders.swift │ │ ├── HTTPMethod.swift │ │ ├── MultipartFormData.swift │ │ ├── MultipartUpload.swift │ │ ├── NetworkReachabilityManager.swift │ │ ├── Notifications.swift │ │ ├── OperationQueue+Alamofire.swift │ │ ├── ParameterEncoder.swift │ │ ├── ParameterEncoding.swift │ │ ├── Protected.swift │ │ ├── RedirectHandler.swift │ │ ├── Request.swift │ │ ├── RequestInterceptor.swift │ │ ├── RequestTaskMap.swift │ │ ├── Response.swift │ │ ├── ResponseSerialization.swift │ │ ├── Result+Alamofire.swift │ │ ├── RetryPolicy.swift │ │ ├── ServerTrustEvaluation.swift │ │ ├── Session.swift │ │ ├── SessionDelegate.swift │ │ ├── StringEncoding+Alamofire.swift │ │ ├── URLConvertible+URLRequestConvertible.swift │ │ ├── URLEncodedFormEncoder.swift │ │ ├── URLRequest+Alamofire.swift │ │ ├── URLSessionConfiguration+Alamofire.swift │ │ └── Validation.swift ├── Manifest.lock ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── omarmhaimdat.xcuserdatad │ │ └── xcschemes │ │ ├── Alamofire.xcscheme │ │ ├── Pods-segmentation_api.xcscheme │ │ └── xcschememanagement.plist └── Target Support Files │ ├── Alamofire │ ├── Alamofire-Info.plist │ ├── Alamofire-dummy.m │ ├── Alamofire-prefix.pch │ ├── Alamofire-umbrella.h │ ├── Alamofire.debug.xcconfig │ ├── Alamofire.modulemap │ └── Alamofire.release.xcconfig │ └── Pods-segmentation_api │ ├── Pods-segmentation_api-Info.plist │ ├── Pods-segmentation_api-acknowledgements.markdown │ ├── Pods-segmentation_api-acknowledgements.plist │ ├── Pods-segmentation_api-dummy.m │ ├── Pods-segmentation_api-frameworks-Debug-input-files.xcfilelist │ ├── Pods-segmentation_api-frameworks-Debug-output-files.xcfilelist │ ├── Pods-segmentation_api-frameworks-Release-input-files.xcfilelist │ ├── Pods-segmentation_api-frameworks-Release-output-files.xcfilelist │ ├── Pods-segmentation_api-frameworks.sh │ ├── Pods-segmentation_api-umbrella.h │ ├── Pods-segmentation_api.debug.xcconfig │ ├── Pods-segmentation_api.modulemap │ └── Pods-segmentation_api.release.xcconfig ├── app.py ├── instance_segmentation.png ├── instance_segmentation_compression_ratio_comparaison.png ├── segmentation_api.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── omarmhaimdat.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── segmentation_api.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── segmentation_api ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-1024.png │ │ ├── Icon-120.png │ │ ├── Icon-121.png │ │ ├── Icon-152.png │ │ ├── Icon-167.png │ │ ├── Icon-180.png │ │ ├── Icon-20.png │ │ ├── Icon-29.png │ │ ├── Icon-40.png │ │ ├── Icon-41.png │ │ ├── Icon-42.png │ │ ├── Icon-58.png │ │ ├── Icon-59.png │ │ ├── Icon-60.png │ │ ├── Icon-76.png │ │ ├── Icon-80.png │ │ ├── Icon-81.png │ │ └── Icon-87.png │ ├── Contents.json │ ├── cover.imageset │ │ ├── Contents.json │ │ └── cover.png │ └── profile.imageset │ │ ├── Contents.json │ │ └── profile.png ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist ├── MyButton.swift ├── OutputViewController.swift ├── SceneDelegate.swift └── ViewController.swift └── semantic_segmentation.png /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'segmentation_api' do 5 | # Comment the next line if you don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for segmentation_api 9 | pod 'Alamofire', '~> 5.2' 10 | 11 | end 12 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (5.2.0) 3 | 4 | DEPENDENCIES: 5 | - Alamofire (~> 5.2) 6 | 7 | SPEC REPOS: 8 | trunk: 9 | - Alamofire 10 | 11 | SPEC CHECKSUMS: 12 | Alamofire: c1ca147559e730bfb2182c8c7aafbdd90a867987 13 | 14 | PODFILE CHECKSUM: ffed80872d7a5ffe5c808454d9d57660affb875f 15 | 16 | COCOAPODS: 1.9.1 17 | -------------------------------------------------------------------------------- /Pods/Alamofire/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2020 Alamofire Software Foundation (http://alamofire.org/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Pods/Alamofire/README.md: -------------------------------------------------------------------------------- 1 | ![Alamofire: Elegant Networking in Swift](https://raw.githubusercontent.com/Alamofire/Alamofire/master/alamofire.png) 2 | 3 | [![Build Status](https://github.com/Alamofire/Alamofire/workflows/Alamofire%20CI/badge.svg?branch=master)](https://github.com/Alamofire/Alamofire/actions) 4 | [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/Alamofire.svg)](https://img.shields.io/cocoapods/v/Alamofire.svg) 5 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 6 | [![Platform](https://img.shields.io/cocoapods/p/Alamofire.svg?style=flat)](https://alamofire.github.io/Alamofire) 7 | [![Twitter](https://img.shields.io/badge/twitter-@AlamofireSF-blue.svg?style=flat)](https://twitter.com/AlamofireSF) 8 | [![Gitter](https://badges.gitter.im/Alamofire/Alamofire.svg)](https://gitter.im/Alamofire/Alamofire?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) 9 | [![Open Source Helpers](https://www.codetriage.com/alamofire/alamofire/badges/users.svg)](https://www.codetriage.com/alamofire/alamofire) 10 | 11 | Alamofire is an HTTP networking library written in Swift. 12 | 13 | - [Features](#features) 14 | - [Component Libraries](#component-libraries) 15 | - [Requirements](#requirements) 16 | - [Migration Guides](#migration-guides) 17 | - [Communication](#communication) 18 | - [Installation](#installation) 19 | - [Usage](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#using-alamofire) 20 | - [**Introduction -**](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#introduction) [Making Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#making-requests), [Response Handling](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-handling), [Response Validation](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-validation), [Response Caching](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-caching) 21 | - **HTTP -** [HTTP Methods](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#http-methods), [Parameters and Parameter Encoder](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md##request-parameters-and-parameter-encoders), [HTTP Headers](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#http-headers), [Authentication](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#authentication) 22 | - **Large Data -** [Downloading Data to a File](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#downloading-data-to-a-file), [Uploading Data to a Server](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#uploading-data-to-a-server) 23 | - **Tools -** [Statistical Metrics](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#statistical-metrics), [cURL Command Output](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#curl-command-output) 24 | - [Advanced Usage](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md) 25 | - **URL Session -** [Session Manager](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#session), [Session Delegate](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#sessiondelegate), [Request](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#request) 26 | - **Routing -** [Routing Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#routing-requests), [Adapting and Retrying Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#adapting-and-retrying-requests-with-requestinterceptor) 27 | - **Model Objects -** [Custom Response Serialization](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#custom-response-serialization) 28 | - **Connection -** [Security](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#security), [Network Reachability](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#network-reachability) 29 | - [Open Radars](#open-radars) 30 | - [FAQ](#faq) 31 | - [Credits](#credits) 32 | - [Donations](#donations) 33 | - [License](#license) 34 | 35 | ## Features 36 | 37 | - [x] Chainable Request / Response Methods 38 | - [x] Combine Support 39 | - [x] URL / JSON Parameter Encoding 40 | - [x] Upload File / Data / Stream / MultipartFormData 41 | - [x] Download File using Request or Resume Data 42 | - [x] Authentication with `URLCredential` 43 | - [x] HTTP Response Validation 44 | - [x] Upload and Download Progress Closures with Progress 45 | - [x] cURL Command Output 46 | - [x] Dynamically Adapt and Retry Requests 47 | - [x] TLS Certificate and Public Key Pinning 48 | - [x] Network Reachability 49 | - [x] Comprehensive Unit and Integration Test Coverage 50 | - [x] [Complete Documentation](https://alamofire.github.io/Alamofire) 51 | 52 | ## Component Libraries 53 | 54 | In order to keep Alamofire focused specifically on core networking implementations, additional component libraries have been created by the [Alamofire Software Foundation](https://github.com/Alamofire/Foundation) to bring additional functionality to the Alamofire ecosystem. 55 | 56 | - [AlamofireImage](https://github.com/Alamofire/AlamofireImage) - An image library including image response serializers, `UIImage` and `UIImageView` extensions, custom image filters, an auto-purging in-memory cache and a priority-based image downloading system. 57 | - [AlamofireNetworkActivityIndicator](https://github.com/Alamofire/AlamofireNetworkActivityIndicator) - Controls the visibility of the network activity indicator on iOS using Alamofire. It contains configurable delay timers to help mitigate flicker and can support `URLSession` instances not managed by Alamofire. 58 | 59 | ## Requirements 60 | 61 | - iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ 62 | - Xcode 11+ 63 | - Swift 5.1+ 64 | 65 | ## Migration Guides 66 | 67 | - [Alamofire 5.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%205.0%20Migration%20Guide.md) 68 | - [Alamofire 4.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%204.0%20Migration%20Guide.md) 69 | - [Alamofire 3.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%203.0%20Migration%20Guide.md) 70 | - [Alamofire 2.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%202.0%20Migration%20Guide.md) 71 | 72 | ## Communication 73 | - If you **need help with making network requests** using Alamofire, use [Stack Overflow](https://stackoverflow.com/questions/tagged/alamofire) and tag `alamofire`. 74 | - If you need to **find or understand an API**, check [our documentation](http://alamofire.github.io/Alamofire/) or [Apple's documentation for `URLSession`](https://developer.apple.com/documentation/foundation/url_loading_system), on top of which Alamofire is built. 75 | - If you need **help with an Alamofire feature**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire). 76 | - If you'd like to **discuss Alamofire best practices**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire). 77 | - If you'd like to **discuss a feature request**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire). 78 | - If you **found a bug**, open an issue here on GitHub and follow the guide. The more detail the better! 79 | - If you **want to contribute**, submit a pull request! 80 | 81 | ## Installation 82 | 83 | ### CocoaPods 84 | 85 | [CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate Alamofire into your Xcode project using CocoaPods, specify it in your `Podfile`: 86 | 87 | ```ruby 88 | pod 'Alamofire', '~> 5.2' 89 | ``` 90 | 91 | ### Carthage 92 | 93 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Alamofire into your Xcode project using Carthage, specify it in your `Cartfile`: 94 | 95 | ```ogdl 96 | github "Alamofire/Alamofire" ~> 5.2 97 | ``` 98 | 99 | ### Swift Package Manager 100 | 101 | The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. It is in early development, but Alamofire does support its use on supported platforms. 102 | 103 | Once you have your Swift package set up, adding Alamofire as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. 104 | 105 | ```swift 106 | dependencies: [ 107 | .package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.2.0")) 108 | ] 109 | ``` 110 | 111 | ### Manually 112 | 113 | If you prefer not to use any of the aforementioned dependency managers, you can integrate Alamofire into your project manually. 114 | 115 | #### Embedded Framework 116 | 117 | - Open up Terminal, `cd` into your top-level project directory, and run the following command "if" your project is not initialized as a git repository: 118 | 119 | ```bash 120 | $ git init 121 | ``` 122 | 123 | - Add Alamofire as a git [submodule](https://git-scm.com/docs/git-submodule) by running the following command: 124 | 125 | ```bash 126 | $ git submodule add https://github.com/Alamofire/Alamofire.git 127 | ``` 128 | 129 | - Open the new `Alamofire` folder, and drag the `Alamofire.xcodeproj` into the Project Navigator of your application's Xcode project. 130 | 131 | > It should appear nested underneath your application's blue project icon. Whether it is above or below all the other Xcode groups does not matter. 132 | 133 | - Select the `Alamofire.xcodeproj` in the Project Navigator and verify the deployment target matches that of your application target. 134 | - Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the "Targets" heading in the sidebar. 135 | - In the tab bar at the top of that window, open the "General" panel. 136 | - Click on the `+` button under the "Embedded Binaries" section. 137 | - You will see two different `Alamofire.xcodeproj` folders each with two different versions of the `Alamofire.framework` nested inside a `Products` folder. 138 | 139 | > It does not matter which `Products` folder you choose from, but it does matter whether you choose the top or bottom `Alamofire.framework`. 140 | 141 | - Select the top `Alamofire.framework` for iOS and the bottom one for macOS. 142 | 143 | > You can verify which one you selected by inspecting the build log for your project. The build target for `Alamofire` will be listed as either `Alamofire iOS`, `Alamofire macOS`, `Alamofire tvOS` or `Alamofire watchOS`. 144 | 145 | - And that's it! 146 | 147 | > The `Alamofire.framework` is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device. 148 | 149 | ## Open Radars 150 | 151 | The following radars have some effect on the current implementation of Alamofire. 152 | 153 | - [`rdar://21349340`](http://www.openradar.me/radar?id=5517037090635776) - Compiler throwing warning due to toll-free bridging issue in test case 154 | - `rdar://26870455` - Background URL Session Configurations do not work in the simulator 155 | - `rdar://26849668` - Some URLProtocol APIs do not properly handle `URLRequest` 156 | - `FB7624529` - `urlSession(_:task:didFinishCollecting:)` never called on watchOS 157 | 158 | ## Resolved Radars 159 | 160 | The following radars have been resolved over time after being filed against the Alamofire project. 161 | 162 | - [`rdar://26761490`](http://www.openradar.me/radar?id=5010235949318144) - Swift string interpolation causing memory leak with common usage. 163 | - (Resolved): 9/1/17 in Xcode 9 beta 6. 164 | - [`rdar://36082113`](http://openradar.appspot.com/radar?id=4942308441063424) - `URLSessionTaskMetrics` failing to link on watchOS 3.0+ 165 | - (Resolved): Just add `CFNetwork` to your linked frameworks. 166 | 167 | ## Workarounds 168 | 169 | - Collection of `URLSessionTaskMetrics` is currently disabled on watchOS due to `FB7624529`. 170 | 171 | ## FAQ 172 | 173 | ### What's the origin of the name Alamofire? 174 | 175 | Alamofire is named after the [Alamo Fire flower](https://aggie-horticulture.tamu.edu/wildseed/alamofire.html), a hybrid variant of the Bluebonnet, the official state flower of Texas. 176 | 177 | ## Credits 178 | 179 | Alamofire is owned and maintained by the [Alamofire Software Foundation](http://alamofire.org). You can follow them on Twitter at [@AlamofireSF](https://twitter.com/AlamofireSF) for project updates and releases. 180 | 181 | ### Security Disclosure 182 | 183 | If you believe you have identified a security vulnerability with Alamofire, you should report it as soon as possible via email to security@alamofire.org. Please do not post it to a public issue tracker. 184 | 185 | ## Donations 186 | 187 | The [ASF](https://github.com/Alamofire/Foundation#members) is looking to raise money to officially stay registered as a federal non-profit organization. 188 | Registering will allow us members to gain some legal protections and also allow us to put donations to use, tax-free. 189 | Donating to the ASF will enable us to: 190 | 191 | - Pay our yearly legal fees to keep the non-profit in good status 192 | - Pay for our mail servers to help us stay on top of all questions and security issues 193 | - Potentially fund test servers to make it easier for us to test the edge cases 194 | - Potentially fund developers to work on one of our projects full-time 195 | 196 | The community adoption of the ASF libraries has been amazing. 197 | We are greatly humbled by your enthusiasm around the projects and want to continue to do everything we can to move the needle forward. 198 | With your continued support, the ASF will be able to improve its reach and also provide better legal safety for the core members. 199 | If you use any of our libraries for work, see if your employers would be interested in donating. 200 | Any amount you can donate today to help us reach our goal would be greatly appreciated. 201 | 202 | [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W34WPEE74APJQ) 203 | 204 | ## License 205 | 206 | Alamofire is released under the MIT license. [See LICENSE](https://github.com/Alamofire/Alamofire/blob/master/LICENSE) for details. 207 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/Alamofire.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Alamofire.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | /// Reference to `Session.default` for quick bootstrapping and examples. 26 | public let AF = Session.default 27 | 28 | /// Current Alamofire version. Necessary since SPM doesn't use dynamic libraries. Plus this will be more accurate. 29 | let version = "5.1.0" 30 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/AlamofireExtended.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlamofireExtended.swift 3 | // 4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | /// Type that acts as a generic extension point for all `AlamofireExtended` types. 26 | public struct AlamofireExtension { 27 | /// Stores the type or meta-type of any extended type. 28 | public private(set) var type: ExtendedType 29 | 30 | /// Create an instance from the provided value. 31 | /// 32 | /// - Parameter type: Instance being extended. 33 | public init(_ type: ExtendedType) { 34 | self.type = type 35 | } 36 | } 37 | 38 | /// Protocol describing the `af` extension points for Alamofire extended types. 39 | public protocol AlamofireExtended { 40 | /// Type being extended. 41 | associatedtype ExtendedType 42 | 43 | /// Static Alamofire extension point. 44 | static var af: AlamofireExtension.Type { get set } 45 | /// Instance Alamofire extension point. 46 | var af: AlamofireExtension { get set } 47 | } 48 | 49 | public extension AlamofireExtended { 50 | /// Static Alamofire extension point. 51 | static var af: AlamofireExtension.Type { 52 | get { AlamofireExtension.self } 53 | set {} 54 | } 55 | 56 | /// Instance Alamofire extension point. 57 | var af: AlamofireExtension { 58 | get { AlamofireExtension(self) } 59 | set {} 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/CachedResponseHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CachedResponseHandler.swift 3 | // 4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// A type that handles whether the data task should store the HTTP response in the cache. 28 | public protocol CachedResponseHandler { 29 | /// Determines whether the HTTP response should be stored in the cache. 30 | /// 31 | /// The `completion` closure should be passed one of three possible options: 32 | /// 33 | /// 1. The cached response provided by the server (this is the most common use case). 34 | /// 2. A modified version of the cached response (you may want to modify it in some way before caching). 35 | /// 3. A `nil` value to prevent the cached response from being stored in the cache. 36 | /// 37 | /// - Parameters: 38 | /// - task: The data task whose request resulted in the cached response. 39 | /// - response: The cached response to potentially store in the cache. 40 | /// - completion: The closure to execute containing cached response, a modified response, or `nil`. 41 | func dataTask(_ task: URLSessionDataTask, 42 | willCacheResponse response: CachedURLResponse, 43 | completion: @escaping (CachedURLResponse?) -> Void) 44 | } 45 | 46 | // MARK: - 47 | 48 | /// `ResponseCacher` is a convenience `CachedResponseHandler` making it easy to cache, not cache, or modify a cached 49 | /// response. 50 | public struct ResponseCacher { 51 | /// Defines the behavior of the `ResponseCacher` type. 52 | public enum Behavior { 53 | /// Stores the cached response in the cache. 54 | case cache 55 | /// Prevents the cached response from being stored in the cache. 56 | case doNotCache 57 | /// Modifies the cached response before storing it in the cache. 58 | case modify((URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?) 59 | } 60 | 61 | /// Returns a `ResponseCacher` with a follow `Behavior`. 62 | public static let cache = ResponseCacher(behavior: .cache) 63 | /// Returns a `ResponseCacher` with a do not follow `Behavior`. 64 | public static let doNotCache = ResponseCacher(behavior: .doNotCache) 65 | 66 | /// The `Behavior` of the `ResponseCacher`. 67 | public let behavior: Behavior 68 | 69 | /// Creates a `ResponseCacher` instance from the `Behavior`. 70 | /// 71 | /// - Parameter behavior: The `Behavior`. 72 | public init(behavior: Behavior) { 73 | self.behavior = behavior 74 | } 75 | } 76 | 77 | extension ResponseCacher: CachedResponseHandler { 78 | public func dataTask(_ task: URLSessionDataTask, 79 | willCacheResponse response: CachedURLResponse, 80 | completion: @escaping (CachedURLResponse?) -> Void) { 81 | switch behavior { 82 | case .cache: 83 | completion(response) 84 | case .doNotCache: 85 | completion(nil) 86 | case let .modify(closure): 87 | let response = closure(task, response) 88 | completion(response) 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/DispatchQueue+Alamofire.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DispatchQueue+Alamofire.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Dispatch 26 | import Foundation 27 | 28 | extension DispatchQueue { 29 | /// Execute the provided closure after a `TimeInterval`. 30 | /// 31 | /// - Parameters: 32 | /// - delay: `TimeInterval` to delay execution. 33 | /// - closure: Closure to execute. 34 | func after(_ delay: TimeInterval, execute closure: @escaping () -> Void) { 35 | asyncAfter(deadline: .now() + delay, execute: closure) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/HTTPMethod.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HTTPMethod.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | /// Type representing HTTP methods. Raw `String` value is stored and compared case-sensitively, so 26 | /// `HTTPMethod.get != HTTPMethod(rawValue: "get")`. 27 | /// 28 | /// See https://tools.ietf.org/html/rfc7231#section-4.3 29 | public struct HTTPMethod: RawRepresentable, Equatable, Hashable { 30 | /// `CONNECT` method. 31 | public static let connect = HTTPMethod(rawValue: "CONNECT") 32 | /// `DELETE` method. 33 | public static let delete = HTTPMethod(rawValue: "DELETE") 34 | /// `GET` method. 35 | public static let get = HTTPMethod(rawValue: "GET") 36 | /// `HEAD` method. 37 | public static let head = HTTPMethod(rawValue: "HEAD") 38 | /// `OPTIONS` method. 39 | public static let options = HTTPMethod(rawValue: "OPTIONS") 40 | /// `PATCH` method. 41 | public static let patch = HTTPMethod(rawValue: "PATCH") 42 | /// `POST` method. 43 | public static let post = HTTPMethod(rawValue: "POST") 44 | /// `PUT` method. 45 | public static let put = HTTPMethod(rawValue: "PUT") 46 | /// `TRACE` method. 47 | public static let trace = HTTPMethod(rawValue: "TRACE") 48 | 49 | public let rawValue: String 50 | 51 | public init(rawValue: String) { 52 | self.rawValue = rawValue 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/MultipartUpload.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultipartUpload.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// Internal type which encapsulates a `MultipartFormData` upload. 28 | final class MultipartUpload { 29 | lazy var result = Result { try build() } 30 | 31 | let isInBackgroundSession: Bool 32 | let multipartFormData: MultipartFormData 33 | let encodingMemoryThreshold: UInt64 34 | let request: URLRequestConvertible 35 | let fileManager: FileManager 36 | 37 | init(isInBackgroundSession: Bool, 38 | encodingMemoryThreshold: UInt64, 39 | request: URLRequestConvertible, 40 | multipartFormData: MultipartFormData) { 41 | self.isInBackgroundSession = isInBackgroundSession 42 | self.encodingMemoryThreshold = encodingMemoryThreshold 43 | self.request = request 44 | fileManager = multipartFormData.fileManager 45 | self.multipartFormData = multipartFormData 46 | } 47 | 48 | func build() throws -> (request: URLRequest, uploadable: UploadRequest.Uploadable) { 49 | var urlRequest = try request.asURLRequest() 50 | urlRequest.setValue(multipartFormData.contentType, forHTTPHeaderField: "Content-Type") 51 | 52 | let uploadable: UploadRequest.Uploadable 53 | if multipartFormData.contentLength < encodingMemoryThreshold && !isInBackgroundSession { 54 | let data = try multipartFormData.encode() 55 | 56 | uploadable = .data(data) 57 | } else { 58 | let tempDirectoryURL = fileManager.temporaryDirectory 59 | let directoryURL = tempDirectoryURL.appendingPathComponent("org.alamofire.manager/multipart.form.data") 60 | let fileName = UUID().uuidString 61 | let fileURL = directoryURL.appendingPathComponent(fileName) 62 | 63 | try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil) 64 | 65 | do { 66 | try multipartFormData.writeEncodedData(to: fileURL) 67 | } catch { 68 | // Cleanup after attempted write if it fails. 69 | try? fileManager.removeItem(at: fileURL) 70 | } 71 | 72 | uploadable = .file(fileURL, shouldRemove: true) 73 | } 74 | 75 | return (request: urlRequest, uploadable: uploadable) 76 | } 77 | } 78 | 79 | extension MultipartUpload: UploadConvertible { 80 | func asURLRequest() throws -> URLRequest { 81 | try result.get().request 82 | } 83 | 84 | func createUploadable() throws -> UploadRequest.Uploadable { 85 | try result.get().uploadable 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/NetworkReachabilityManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkReachabilityManager.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | #if !(os(watchOS) || os(Linux)) 26 | 27 | import Foundation 28 | import SystemConfiguration 29 | 30 | /// The `NetworkReachabilityManager` class listens for reachability changes of hosts and addresses for both cellular and 31 | /// WiFi network interfaces. 32 | /// 33 | /// Reachability can be used to determine background information about why a network operation failed, or to retry 34 | /// network requests when a connection is established. It should not be used to prevent a user from initiating a network 35 | /// request, as it's possible that an initial request may be required to establish reachability. 36 | open class NetworkReachabilityManager { 37 | /// Defines the various states of network reachability. 38 | public enum NetworkReachabilityStatus { 39 | /// It is unknown whether the network is reachable. 40 | case unknown 41 | /// The network is not reachable. 42 | case notReachable 43 | /// The network is reachable on the associated `ConnectionType`. 44 | case reachable(ConnectionType) 45 | 46 | init(_ flags: SCNetworkReachabilityFlags) { 47 | guard flags.isActuallyReachable else { self = .notReachable; return } 48 | 49 | var networkStatus: NetworkReachabilityStatus = .reachable(.ethernetOrWiFi) 50 | 51 | if flags.isCellular { networkStatus = .reachable(.cellular) } 52 | 53 | self = networkStatus 54 | } 55 | 56 | /// Defines the various connection types detected by reachability flags. 57 | public enum ConnectionType { 58 | /// The connection type is either over Ethernet or WiFi. 59 | case ethernetOrWiFi 60 | /// The connection type is a cellular connection. 61 | case cellular 62 | } 63 | } 64 | 65 | /// A closure executed when the network reachability status changes. The closure takes a single argument: the 66 | /// network reachability status. 67 | public typealias Listener = (NetworkReachabilityStatus) -> Void 68 | 69 | /// Default `NetworkReachabilityManager` for the zero address and a `listenerQueue` of `.main`. 70 | public static let `default` = NetworkReachabilityManager() 71 | 72 | // MARK: - Properties 73 | 74 | /// Whether the network is currently reachable. 75 | open var isReachable: Bool { isReachableOnCellular || isReachableOnEthernetOrWiFi } 76 | 77 | /// Whether the network is currently reachable over the cellular interface. 78 | /// 79 | /// - Note: Using this property to decide whether to make a high or low bandwidth request is not recommended. 80 | /// Instead, set the `allowsCellularAccess` on any `URLRequest`s being issued. 81 | /// 82 | open var isReachableOnCellular: Bool { status == .reachable(.cellular) } 83 | 84 | /// Whether the network is currently reachable over Ethernet or WiFi interface. 85 | open var isReachableOnEthernetOrWiFi: Bool { status == .reachable(.ethernetOrWiFi) } 86 | 87 | /// `DispatchQueue` on which reachability will update. 88 | public let reachabilityQueue = DispatchQueue(label: "org.alamofire.reachabilityQueue") 89 | 90 | /// Flags of the current reachability type, if any. 91 | open var flags: SCNetworkReachabilityFlags? { 92 | var flags = SCNetworkReachabilityFlags() 93 | 94 | return (SCNetworkReachabilityGetFlags(reachability, &flags)) ? flags : nil 95 | } 96 | 97 | /// The current network reachability status. 98 | open var status: NetworkReachabilityStatus { 99 | flags.map(NetworkReachabilityStatus.init) ?? .unknown 100 | } 101 | 102 | /// Mutable state storage. 103 | struct MutableState { 104 | /// A closure executed when the network reachability status changes. 105 | var listener: Listener? 106 | /// `DispatchQueue` on which listeners will be called. 107 | var listenerQueue: DispatchQueue? 108 | /// Previously calculated status. 109 | var previousStatus: NetworkReachabilityStatus? 110 | } 111 | 112 | /// `SCNetworkReachability` instance providing notifications. 113 | private let reachability: SCNetworkReachability 114 | 115 | /// Protected storage for mutable state. 116 | @Protected 117 | private var mutableState = MutableState() 118 | 119 | // MARK: - Initialization 120 | 121 | /// Creates an instance with the specified host. 122 | /// 123 | /// - Note: The `host` value must *not* contain a scheme, just the hostname. 124 | /// 125 | /// - Parameters: 126 | /// - host: Host used to evaluate network reachability. Must *not* include the scheme (e.g. `https`). 127 | public convenience init?(host: String) { 128 | guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else { return nil } 129 | 130 | self.init(reachability: reachability) 131 | } 132 | 133 | /// Creates an instance that monitors the address 0.0.0.0. 134 | /// 135 | /// Reachability treats the 0.0.0.0 address as a special token that causes it to monitor the general routing 136 | /// status of the device, both IPv4 and IPv6. 137 | public convenience init?() { 138 | var zero = sockaddr() 139 | zero.sa_len = UInt8(MemoryLayout.size) 140 | zero.sa_family = sa_family_t(AF_INET) 141 | 142 | guard let reachability = SCNetworkReachabilityCreateWithAddress(nil, &zero) else { return nil } 143 | 144 | self.init(reachability: reachability) 145 | } 146 | 147 | private init(reachability: SCNetworkReachability) { 148 | self.reachability = reachability 149 | } 150 | 151 | deinit { 152 | stopListening() 153 | } 154 | 155 | // MARK: - Listening 156 | 157 | /// Starts listening for changes in network reachability status. 158 | /// 159 | /// - Note: Stops and removes any existing listener. 160 | /// 161 | /// - Parameters: 162 | /// - queue: `DispatchQueue` on which to call the `listener` closure. `.main` by default. 163 | /// - listener: `Listener` closure called when reachability changes. 164 | /// 165 | /// - Returns: `true` if listening was started successfully, `false` otherwise. 166 | @discardableResult 167 | open func startListening(onQueue queue: DispatchQueue = .main, 168 | onUpdatePerforming listener: @escaping Listener) -> Bool { 169 | stopListening() 170 | 171 | $mutableState.write { state in 172 | state.listenerQueue = queue 173 | state.listener = listener 174 | } 175 | 176 | var context = SCNetworkReachabilityContext(version: 0, 177 | info: Unmanaged.passUnretained(self).toOpaque(), 178 | retain: nil, 179 | release: nil, 180 | copyDescription: nil) 181 | let callback: SCNetworkReachabilityCallBack = { _, flags, info in 182 | guard let info = info else { return } 183 | 184 | let instance = Unmanaged.fromOpaque(info).takeUnretainedValue() 185 | instance.notifyListener(flags) 186 | } 187 | 188 | let queueAdded = SCNetworkReachabilitySetDispatchQueue(reachability, reachabilityQueue) 189 | let callbackAdded = SCNetworkReachabilitySetCallback(reachability, callback, &context) 190 | 191 | // Manually call listener to give initial state, since the framework may not. 192 | if let currentFlags = flags { 193 | reachabilityQueue.async { 194 | self.notifyListener(currentFlags) 195 | } 196 | } 197 | 198 | return callbackAdded && queueAdded 199 | } 200 | 201 | /// Stops listening for changes in network reachability status. 202 | open func stopListening() { 203 | SCNetworkReachabilitySetCallback(reachability, nil, nil) 204 | SCNetworkReachabilitySetDispatchQueue(reachability, nil) 205 | $mutableState.write { state in 206 | state.listener = nil 207 | state.listenerQueue = nil 208 | state.previousStatus = nil 209 | } 210 | } 211 | 212 | // MARK: - Internal - Listener Notification 213 | 214 | /// Calls the `listener` closure of the `listenerQueue` if the computed status hasn't changed. 215 | /// 216 | /// - Note: Should only be called from the `reachabilityQueue`. 217 | /// 218 | /// - Parameter flags: `SCNetworkReachabilityFlags` to use to calculate the status. 219 | func notifyListener(_ flags: SCNetworkReachabilityFlags) { 220 | let newStatus = NetworkReachabilityStatus(flags) 221 | 222 | $mutableState.write { state in 223 | guard state.previousStatus != newStatus else { return } 224 | 225 | state.previousStatus = newStatus 226 | 227 | let listener = state.listener 228 | state.listenerQueue?.async { listener?(newStatus) } 229 | } 230 | } 231 | } 232 | 233 | // MARK: - 234 | 235 | extension NetworkReachabilityManager.NetworkReachabilityStatus: Equatable {} 236 | 237 | extension SCNetworkReachabilityFlags { 238 | var isReachable: Bool { contains(.reachable) } 239 | var isConnectionRequired: Bool { contains(.connectionRequired) } 240 | var canConnectAutomatically: Bool { contains(.connectionOnDemand) || contains(.connectionOnTraffic) } 241 | var canConnectWithoutUserInteraction: Bool { canConnectAutomatically && !contains(.interventionRequired) } 242 | var isActuallyReachable: Bool { isReachable && (!isConnectionRequired || canConnectWithoutUserInteraction) } 243 | var isCellular: Bool { 244 | #if os(iOS) || os(tvOS) 245 | return contains(.isWWAN) 246 | #else 247 | return false 248 | #endif 249 | } 250 | 251 | /// Human readable `String` for all states, to help with debugging. 252 | var readableDescription: String { 253 | let W = isCellular ? "W" : "-" 254 | let R = isReachable ? "R" : "-" 255 | let c = isConnectionRequired ? "c" : "-" 256 | let t = contains(.transientConnection) ? "t" : "-" 257 | let i = contains(.interventionRequired) ? "i" : "-" 258 | let C = contains(.connectionOnTraffic) ? "C" : "-" 259 | let D = contains(.connectionOnDemand) ? "D" : "-" 260 | let l = contains(.isLocalAddress) ? "l" : "-" 261 | let d = contains(.isDirect) ? "d" : "-" 262 | let a = contains(.connectionAutomatic) ? "a" : "-" 263 | 264 | return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)\(a)" 265 | } 266 | } 267 | #endif 268 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/Notifications.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Notifications.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | public extension Request { 28 | /// Posted when a `Request` is resumed. The `Notification` contains the resumed `Request`. 29 | static let didResumeNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didResume") 30 | /// Posted when a `Request` is suspended. The `Notification` contains the suspended `Request`. 31 | static let didSuspendNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didSuspend") 32 | /// Posted when a `Request` is cancelled. The `Notification` contains the cancelled `Request`. 33 | static let didCancelNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didCancel") 34 | /// Posted when a `Request` is finished. The `Notification` contains the completed `Request`. 35 | static let didFinishNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didFinish") 36 | 37 | /// Posted when a `URLSessionTask` is resumed. The `Notification` contains the `Request` associated with the `URLSessionTask`. 38 | static let didResumeTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didResumeTask") 39 | /// Posted when a `URLSessionTask` is suspended. The `Notification` contains the `Request` associated with the `URLSessionTask`. 40 | static let didSuspendTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didSuspendTask") 41 | /// Posted when a `URLSessionTask` is cancelled. The `Notification` contains the `Request` associated with the `URLSessionTask`. 42 | static let didCancelTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didCancelTask") 43 | /// Posted when a `URLSessionTask` is completed. The `Notification` contains the `Request` associated with the `URLSessionTask`. 44 | static let didCompleteTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didCompleteTask") 45 | } 46 | 47 | // MARK: - 48 | 49 | extension Notification { 50 | /// The `Request` contained by the instance's `userInfo`, `nil` otherwise. 51 | public var request: Request? { 52 | userInfo?[String.requestKey] as? Request 53 | } 54 | 55 | /// Convenience initializer for a `Notification` containing a `Request` payload. 56 | /// 57 | /// - Parameters: 58 | /// - name: The name of the notification. 59 | /// - request: The `Request` payload. 60 | init(name: Notification.Name, request: Request) { 61 | self.init(name: name, object: nil, userInfo: [String.requestKey: request]) 62 | } 63 | } 64 | 65 | extension NotificationCenter { 66 | /// Convenience function for posting notifications with `Request` payloads. 67 | /// 68 | /// - Parameters: 69 | /// - name: The name of the notification. 70 | /// - request: The `Request` payload. 71 | func postNotification(named name: Notification.Name, with request: Request) { 72 | let notification = Notification(name: name, request: request) 73 | post(notification) 74 | } 75 | } 76 | 77 | extension String { 78 | /// User info dictionary key representing the `Request` associated with the notification. 79 | fileprivate static let requestKey = "org.alamofire.notification.key.request" 80 | } 81 | 82 | /// `EventMonitor` that provides Alamofire's notifications. 83 | public final class AlamofireNotifications: EventMonitor { 84 | public func requestDidResume(_ request: Request) { 85 | NotificationCenter.default.postNotification(named: Request.didResumeNotification, with: request) 86 | } 87 | 88 | public func requestDidSuspend(_ request: Request) { 89 | NotificationCenter.default.postNotification(named: Request.didSuspendNotification, with: request) 90 | } 91 | 92 | public func requestDidCancel(_ request: Request) { 93 | NotificationCenter.default.postNotification(named: Request.didCancelNotification, with: request) 94 | } 95 | 96 | public func requestDidFinish(_ request: Request) { 97 | NotificationCenter.default.postNotification(named: Request.didFinishNotification, with: request) 98 | } 99 | 100 | public func request(_ request: Request, didResumeTask task: URLSessionTask) { 101 | NotificationCenter.default.postNotification(named: Request.didResumeTaskNotification, with: request) 102 | } 103 | 104 | public func request(_ request: Request, didSuspendTask task: URLSessionTask) { 105 | NotificationCenter.default.postNotification(named: Request.didSuspendTaskNotification, with: request) 106 | } 107 | 108 | public func request(_ request: Request, didCancelTask task: URLSessionTask) { 109 | NotificationCenter.default.postNotification(named: Request.didCancelTaskNotification, with: request) 110 | } 111 | 112 | public func request(_ request: Request, didCompleteTask task: URLSessionTask, with error: AFError?) { 113 | NotificationCenter.default.postNotification(named: Request.didCompleteTaskNotification, with: request) 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/OperationQueue+Alamofire.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OperationQueue+Alamofire.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | extension OperationQueue { 28 | /// Creates an instance using the provided parameters. 29 | /// 30 | /// - Parameters: 31 | /// - qualityOfService: `QualityOfService` to be applied to the queue. `.default` by default. 32 | /// - maxConcurrentOperationCount: Maximum concurrent operations. 33 | /// `OperationQueue.defaultMaxConcurrentOperationCount` by default. 34 | /// - underlyingQueue: Underlying `DispatchQueue`. `nil` by default. 35 | /// - name: Name for the queue. `nil` by default. 36 | /// - startSuspended: Whether the queue starts suspended. `false` by default. 37 | convenience init(qualityOfService: QualityOfService = .default, 38 | maxConcurrentOperationCount: Int = OperationQueue.defaultMaxConcurrentOperationCount, 39 | underlyingQueue: DispatchQueue? = nil, 40 | name: String? = nil, 41 | startSuspended: Bool = false) { 42 | self.init() 43 | self.qualityOfService = qualityOfService 44 | self.maxConcurrentOperationCount = maxConcurrentOperationCount 45 | self.underlyingQueue = underlyingQueue 46 | self.name = name 47 | isSuspended = startSuspended 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/ParameterEncoder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ParameterEncoder.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// A type that can encode any `Encodable` type into a `URLRequest`. 28 | public protocol ParameterEncoder { 29 | /// Encode the provided `Encodable` parameters into `request`. 30 | /// 31 | /// - Parameters: 32 | /// - parameters: The `Encodable` parameter value. 33 | /// - request: The `URLRequest` into which to encode the parameters. 34 | /// 35 | /// - Returns: A `URLRequest` with the result of the encoding. 36 | /// - Throws: An `Error` when encoding fails. For Alamofire provided encoders, this will be an instance of 37 | /// `AFError.parameterEncoderFailed` with an associated `ParameterEncoderFailureReason`. 38 | func encode(_ parameters: Parameters?, into request: URLRequest) throws -> URLRequest 39 | } 40 | 41 | /// A `ParameterEncoder` that encodes types as JSON body data. 42 | /// 43 | /// If no `Content-Type` header is already set on the provided `URLRequest`s, it's set to `application/json`. 44 | open class JSONParameterEncoder: ParameterEncoder { 45 | /// Returns an encoder with default parameters. 46 | public static var `default`: JSONParameterEncoder { JSONParameterEncoder() } 47 | 48 | /// Returns an encoder with `JSONEncoder.outputFormatting` set to `.prettyPrinted`. 49 | public static var prettyPrinted: JSONParameterEncoder { 50 | let encoder = JSONEncoder() 51 | encoder.outputFormatting = .prettyPrinted 52 | 53 | return JSONParameterEncoder(encoder: encoder) 54 | } 55 | 56 | /// Returns an encoder with `JSONEncoder.outputFormatting` set to `.sortedKeys`. 57 | @available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) 58 | public static var sortedKeys: JSONParameterEncoder { 59 | let encoder = JSONEncoder() 60 | encoder.outputFormatting = .sortedKeys 61 | 62 | return JSONParameterEncoder(encoder: encoder) 63 | } 64 | 65 | /// `JSONEncoder` used to encode parameters. 66 | public let encoder: JSONEncoder 67 | 68 | /// Creates an instance with the provided `JSONEncoder`. 69 | /// 70 | /// - Parameter encoder: The `JSONEncoder`. `JSONEncoder()` by default. 71 | public init(encoder: JSONEncoder = JSONEncoder()) { 72 | self.encoder = encoder 73 | } 74 | 75 | open func encode(_ parameters: Parameters?, 76 | into request: URLRequest) throws -> URLRequest { 77 | guard let parameters = parameters else { return request } 78 | 79 | var request = request 80 | 81 | do { 82 | let data = try encoder.encode(parameters) 83 | request.httpBody = data 84 | if request.headers["Content-Type"] == nil { 85 | request.headers.update(.contentType("application/json")) 86 | } 87 | } catch { 88 | throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) 89 | } 90 | 91 | return request 92 | } 93 | } 94 | 95 | /// A `ParameterEncoder` that encodes types as URL-encoded query strings to be set on the URL or as body data, depending 96 | /// on the `Destination` set. 97 | /// 98 | /// If no `Content-Type` header is already set on the provided `URLRequest`s, it will be set to 99 | /// `application/x-www-form-urlencoded; charset=utf-8`. 100 | /// 101 | /// Encoding behavior can be customized by passing an instance of `URLEncodedFormEncoder` to the initializer. 102 | open class URLEncodedFormParameterEncoder: ParameterEncoder { 103 | /// Defines where the URL-encoded string should be set for each `URLRequest`. 104 | public enum Destination { 105 | /// Applies the encoded query string to any existing query string for `.get`, `.head`, and `.delete` request. 106 | /// Sets it to the `httpBody` for all other methods. 107 | case methodDependent 108 | /// Applies the encoded query string to any existing query string from the `URLRequest`. 109 | case queryString 110 | /// Applies the encoded query string to the `httpBody` of the `URLRequest`. 111 | case httpBody 112 | 113 | /// Determines whether the URL-encoded string should be applied to the `URLRequest`'s `url`. 114 | /// 115 | /// - Parameter method: The `HTTPMethod`. 116 | /// 117 | /// - Returns: Whether the URL-encoded string should be applied to a `URL`. 118 | func encodesParametersInURL(for method: HTTPMethod) -> Bool { 119 | switch self { 120 | case .methodDependent: return [.get, .head, .delete].contains(method) 121 | case .queryString: return true 122 | case .httpBody: return false 123 | } 124 | } 125 | } 126 | 127 | /// Returns an encoder with default parameters. 128 | public static var `default`: URLEncodedFormParameterEncoder { URLEncodedFormParameterEncoder() } 129 | 130 | /// The `URLEncodedFormEncoder` to use. 131 | public let encoder: URLEncodedFormEncoder 132 | 133 | /// The `Destination` for the URL-encoded string. 134 | public let destination: Destination 135 | 136 | /// Creates an instance with the provided `URLEncodedFormEncoder` instance and `Destination` value. 137 | /// 138 | /// - Parameters: 139 | /// - encoder: The `URLEncodedFormEncoder`. `URLEncodedFormEncoder()` by default. 140 | /// - destination: The `Destination`. `.methodDependent` by default. 141 | public init(encoder: URLEncodedFormEncoder = URLEncodedFormEncoder(), destination: Destination = .methodDependent) { 142 | self.encoder = encoder 143 | self.destination = destination 144 | } 145 | 146 | open func encode(_ parameters: Parameters?, 147 | into request: URLRequest) throws -> URLRequest { 148 | guard let parameters = parameters else { return request } 149 | 150 | var request = request 151 | 152 | guard let url = request.url else { 153 | throw AFError.parameterEncoderFailed(reason: .missingRequiredComponent(.url)) 154 | } 155 | 156 | guard let method = request.method else { 157 | let rawValue = request.method?.rawValue ?? "nil" 158 | throw AFError.parameterEncoderFailed(reason: .missingRequiredComponent(.httpMethod(rawValue: rawValue))) 159 | } 160 | 161 | if destination.encodesParametersInURL(for: method), 162 | var components = URLComponents(url: url, resolvingAgainstBaseURL: false) { 163 | let query: String = try Result { try encoder.encode(parameters) } 164 | .mapError { AFError.parameterEncoderFailed(reason: .encoderFailed(error: $0)) }.get() 165 | let newQueryString = [components.percentEncodedQuery, query].compactMap { $0 }.joinedWithAmpersands() 166 | components.percentEncodedQuery = newQueryString.isEmpty ? nil : newQueryString 167 | 168 | guard let newURL = components.url else { 169 | throw AFError.parameterEncoderFailed(reason: .missingRequiredComponent(.url)) 170 | } 171 | 172 | request.url = newURL 173 | } else { 174 | if request.headers["Content-Type"] == nil { 175 | request.headers.update(.contentType("application/x-www-form-urlencoded; charset=utf-8")) 176 | } 177 | 178 | request.httpBody = try Result { try encoder.encode(parameters) } 179 | .mapError { AFError.parameterEncoderFailed(reason: .encoderFailed(error: $0)) }.get() 180 | } 181 | 182 | return request 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/ParameterEncoding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ParameterEncoding.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// A dictionary of parameters to apply to a `URLRequest`. 28 | public typealias Parameters = [String: Any] 29 | 30 | /// A type used to define how a set of parameters are applied to a `URLRequest`. 31 | public protocol ParameterEncoding { 32 | /// Creates a `URLRequest` by encoding parameters and applying them on the passed request. 33 | /// 34 | /// - Parameters: 35 | /// - urlRequest: `URLRequestConvertible` value onto which parameters will be encoded. 36 | /// - parameters: `Parameters` to encode onto the request. 37 | /// 38 | /// - Returns: The encoded `URLRequest`. 39 | /// - Throws: Any `Error` produced during parameter encoding. 40 | func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest 41 | } 42 | 43 | // MARK: - 44 | 45 | /// Creates a url-encoded query string to be set as or appended to any existing URL query string or set as the HTTP 46 | /// body of the URL request. Whether the query string is set or appended to any existing URL query string or set as 47 | /// the HTTP body depends on the destination of the encoding. 48 | /// 49 | /// The `Content-Type` HTTP header field of an encoded request with HTTP body is set to 50 | /// `application/x-www-form-urlencoded; charset=utf-8`. 51 | /// 52 | /// There is no published specification for how to encode collection types. By default the convention of appending 53 | /// `[]` to the key for array values (`foo[]=1&foo[]=2`), and appending the key surrounded by square brackets for 54 | /// nested dictionary values (`foo[bar]=baz`) is used. Optionally, `ArrayEncoding` can be used to omit the 55 | /// square brackets appended to array keys. 56 | /// 57 | /// `BoolEncoding` can be used to configure how boolean values are encoded. The default behavior is to encode 58 | /// `true` as 1 and `false` as 0. 59 | public struct URLEncoding: ParameterEncoding { 60 | // MARK: Helper Types 61 | 62 | /// Defines whether the url-encoded query string is applied to the existing query string or HTTP body of the 63 | /// resulting URL request. 64 | public enum Destination { 65 | /// Applies encoded query string result to existing query string for `GET`, `HEAD` and `DELETE` requests and 66 | /// sets as the HTTP body for requests with any other HTTP method. 67 | case methodDependent 68 | /// Sets or appends encoded query string result to existing query string. 69 | case queryString 70 | /// Sets encoded query string result as the HTTP body of the URL request. 71 | case httpBody 72 | 73 | func encodesParametersInURL(for method: HTTPMethod) -> Bool { 74 | switch self { 75 | case .methodDependent: return [.get, .head, .delete].contains(method) 76 | case .queryString: return true 77 | case .httpBody: return false 78 | } 79 | } 80 | } 81 | 82 | /// Configures how `Array` parameters are encoded. 83 | public enum ArrayEncoding { 84 | /// An empty set of square brackets is appended to the key for every value. This is the default behavior. 85 | case brackets 86 | /// No brackets are appended. The key is encoded as is. 87 | case noBrackets 88 | 89 | func encode(key: String) -> String { 90 | switch self { 91 | case .brackets: 92 | return "\(key)[]" 93 | case .noBrackets: 94 | return key 95 | } 96 | } 97 | } 98 | 99 | /// Configures how `Bool` parameters are encoded. 100 | public enum BoolEncoding { 101 | /// Encode `true` as `1` and `false` as `0`. This is the default behavior. 102 | case numeric 103 | /// Encode `true` and `false` as string literals. 104 | case literal 105 | 106 | func encode(value: Bool) -> String { 107 | switch self { 108 | case .numeric: 109 | return value ? "1" : "0" 110 | case .literal: 111 | return value ? "true" : "false" 112 | } 113 | } 114 | } 115 | 116 | // MARK: Properties 117 | 118 | /// Returns a default `URLEncoding` instance with a `.methodDependent` destination. 119 | public static var `default`: URLEncoding { URLEncoding() } 120 | 121 | /// Returns a `URLEncoding` instance with a `.queryString` destination. 122 | public static var queryString: URLEncoding { URLEncoding(destination: .queryString) } 123 | 124 | /// Returns a `URLEncoding` instance with an `.httpBody` destination. 125 | public static var httpBody: URLEncoding { URLEncoding(destination: .httpBody) } 126 | 127 | /// The destination defining where the encoded query string is to be applied to the URL request. 128 | public let destination: Destination 129 | 130 | /// The encoding to use for `Array` parameters. 131 | public let arrayEncoding: ArrayEncoding 132 | 133 | /// The encoding to use for `Bool` parameters. 134 | public let boolEncoding: BoolEncoding 135 | 136 | // MARK: Initialization 137 | 138 | /// Creates an instance using the specified parameters. 139 | /// 140 | /// - Parameters: 141 | /// - destination: `Destination` defining where the encoded query string will be applied. `.methodDependent` by 142 | /// default. 143 | /// - arrayEncoding: `ArrayEncoding` to use. `.brackets` by default. 144 | /// - boolEncoding: `BoolEncoding` to use. `.numeric` by default. 145 | public init(destination: Destination = .methodDependent, 146 | arrayEncoding: ArrayEncoding = .brackets, 147 | boolEncoding: BoolEncoding = .numeric) { 148 | self.destination = destination 149 | self.arrayEncoding = arrayEncoding 150 | self.boolEncoding = boolEncoding 151 | } 152 | 153 | // MARK: Encoding 154 | 155 | public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { 156 | var urlRequest = try urlRequest.asURLRequest() 157 | 158 | guard let parameters = parameters else { return urlRequest } 159 | 160 | if let method = urlRequest.method, destination.encodesParametersInURL(for: method) { 161 | guard let url = urlRequest.url else { 162 | throw AFError.parameterEncodingFailed(reason: .missingURL) 163 | } 164 | 165 | if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty { 166 | let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters) 167 | urlComponents.percentEncodedQuery = percentEncodedQuery 168 | urlRequest.url = urlComponents.url 169 | } 170 | } else { 171 | if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { 172 | urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type") 173 | } 174 | 175 | urlRequest.httpBody = Data(query(parameters).utf8) 176 | } 177 | 178 | return urlRequest 179 | } 180 | 181 | /// Creates a percent-escaped, URL encoded query string components from the given key-value pair recursively. 182 | /// 183 | /// - Parameters: 184 | /// - key: Key of the query component. 185 | /// - value: Value of the query component. 186 | /// 187 | /// - Returns: The percent-escaped, URL encoded query string components. 188 | public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] { 189 | var components: [(String, String)] = [] 190 | 191 | if let dictionary = value as? [String: Any] { 192 | for (nestedKey, value) in dictionary { 193 | components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value) 194 | } 195 | } else if let array = value as? [Any] { 196 | for value in array { 197 | components += queryComponents(fromKey: arrayEncoding.encode(key: key), value: value) 198 | } 199 | } else if let value = value as? NSNumber { 200 | if value.isBool { 201 | components.append((escape(key), escape(boolEncoding.encode(value: value.boolValue)))) 202 | } else { 203 | components.append((escape(key), escape("\(value)"))) 204 | } 205 | } else if let bool = value as? Bool { 206 | components.append((escape(key), escape(boolEncoding.encode(value: bool)))) 207 | } else { 208 | components.append((escape(key), escape("\(value)"))) 209 | } 210 | 211 | return components 212 | } 213 | 214 | /// Creates a percent-escaped string following RFC 3986 for a query string key or value. 215 | /// 216 | /// - Parameter string: `String` to be percent-escaped. 217 | /// 218 | /// - Returns: The percent-escaped `String`. 219 | public func escape(_ string: String) -> String { 220 | string.addingPercentEncoding(withAllowedCharacters: .afURLQueryAllowed) ?? string 221 | } 222 | 223 | private func query(_ parameters: [String: Any]) -> String { 224 | var components: [(String, String)] = [] 225 | 226 | for key in parameters.keys.sorted(by: <) { 227 | let value = parameters[key]! 228 | components += queryComponents(fromKey: key, value: value) 229 | } 230 | return components.map { "\($0)=\($1)" }.joined(separator: "&") 231 | } 232 | } 233 | 234 | // MARK: - 235 | 236 | /// Uses `JSONSerialization` to create a JSON representation of the parameters object, which is set as the body of the 237 | /// request. The `Content-Type` HTTP header field of an encoded request is set to `application/json`. 238 | public struct JSONEncoding: ParameterEncoding { 239 | // MARK: Properties 240 | 241 | /// Returns a `JSONEncoding` instance with default writing options. 242 | public static var `default`: JSONEncoding { JSONEncoding() } 243 | 244 | /// Returns a `JSONEncoding` instance with `.prettyPrinted` writing options. 245 | public static var prettyPrinted: JSONEncoding { JSONEncoding(options: .prettyPrinted) } 246 | 247 | /// The options for writing the parameters as JSON data. 248 | public let options: JSONSerialization.WritingOptions 249 | 250 | // MARK: Initialization 251 | 252 | /// Creates an instance using the specified `WritingOptions`. 253 | /// 254 | /// - Parameter options: `JSONSerialization.WritingOptions` to use. 255 | public init(options: JSONSerialization.WritingOptions = []) { 256 | self.options = options 257 | } 258 | 259 | // MARK: Encoding 260 | 261 | public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { 262 | var urlRequest = try urlRequest.asURLRequest() 263 | 264 | guard let parameters = parameters else { return urlRequest } 265 | 266 | do { 267 | let data = try JSONSerialization.data(withJSONObject: parameters, options: options) 268 | 269 | if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { 270 | urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") 271 | } 272 | 273 | urlRequest.httpBody = data 274 | } catch { 275 | throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) 276 | } 277 | 278 | return urlRequest 279 | } 280 | 281 | /// Encodes any JSON compatible object into a `URLRequest`. 282 | /// 283 | /// - Parameters: 284 | /// - urlRequest: `URLRequestConvertible` value into which the object will be encoded. 285 | /// - jsonObject: `Any` value (must be JSON compatible` to be encoded into the `URLRequest`. `nil` by default. 286 | /// 287 | /// - Returns: The encoded `URLRequest`. 288 | /// - Throws: Any `Error` produced during encoding. 289 | public func encode(_ urlRequest: URLRequestConvertible, withJSONObject jsonObject: Any? = nil) throws -> URLRequest { 290 | var urlRequest = try urlRequest.asURLRequest() 291 | 292 | guard let jsonObject = jsonObject else { return urlRequest } 293 | 294 | do { 295 | let data = try JSONSerialization.data(withJSONObject: jsonObject, options: options) 296 | 297 | if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { 298 | urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") 299 | } 300 | 301 | urlRequest.httpBody = data 302 | } catch { 303 | throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) 304 | } 305 | 306 | return urlRequest 307 | } 308 | } 309 | 310 | // MARK: - 311 | 312 | extension NSNumber { 313 | fileprivate var isBool: Bool { 314 | // Use Obj-C type encoding to check whether the underlying type is a `Bool`, as it's guaranteed as part of 315 | // swift-corelibs-foundation, per [this discussion on the Swift forums](https://forums.swift.org/t/alamofire-on-linux-possible-but-not-release-ready/34553/22). 316 | String(cString: objCType) == "c" 317 | } 318 | } 319 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/Protected.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Protected.swift 3 | // 4 | // Copyright (c) 2014-2020 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | private protocol Lock { 28 | func lock() 29 | func unlock() 30 | } 31 | 32 | extension Lock { 33 | /// Executes a closure returning a value while acquiring the lock. 34 | /// 35 | /// - Parameter closure: The closure to run. 36 | /// 37 | /// - Returns: The value the closure generated. 38 | func around(_ closure: () -> T) -> T { 39 | lock(); defer { unlock() } 40 | return closure() 41 | } 42 | 43 | /// Execute a closure while acquiring the lock. 44 | /// 45 | /// - Parameter closure: The closure to run. 46 | func around(_ closure: () -> Void) { 47 | lock(); defer { unlock() } 48 | closure() 49 | } 50 | } 51 | 52 | #if os(Linux) 53 | /// A `pthread_mutex_t` wrapper. 54 | final class MutexLock: Lock { 55 | private var mutex: UnsafeMutablePointer 56 | 57 | init() { 58 | mutex = .allocate(capacity: 1) 59 | 60 | var attr = pthread_mutexattr_t() 61 | pthread_mutexattr_init(&attr) 62 | pthread_mutexattr_settype(&attr, .init(PTHREAD_MUTEX_ERRORCHECK)) 63 | 64 | let error = pthread_mutex_init(mutex, &attr) 65 | precondition(error == 0, "Failed to create pthread_mutex") 66 | } 67 | 68 | deinit { 69 | let error = pthread_mutex_destroy(mutex) 70 | precondition(error == 0, "Failed to destroy pthread_mutex") 71 | } 72 | 73 | fileprivate func lock() { 74 | let error = pthread_mutex_lock(mutex) 75 | precondition(error == 0, "Failed to lock pthread_mutex") 76 | } 77 | 78 | fileprivate func unlock() { 79 | let error = pthread_mutex_unlock(mutex) 80 | precondition(error == 0, "Failed to unlock pthread_mutex") 81 | } 82 | } 83 | #endif 84 | 85 | #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) 86 | /// An `os_unfair_lock` wrapper. 87 | final class UnfairLock: Lock { 88 | private let unfairLock: os_unfair_lock_t 89 | 90 | init() { 91 | unfairLock = .allocate(capacity: 1) 92 | unfairLock.initialize(to: os_unfair_lock()) 93 | } 94 | 95 | deinit { 96 | unfairLock.deinitialize(count: 1) 97 | unfairLock.deallocate() 98 | } 99 | 100 | fileprivate func lock() { 101 | os_unfair_lock_lock(unfairLock) 102 | } 103 | 104 | fileprivate func unlock() { 105 | os_unfair_lock_unlock(unfairLock) 106 | } 107 | } 108 | #endif 109 | 110 | /// A thread-safe wrapper around a value. 111 | @propertyWrapper 112 | @dynamicMemberLookup 113 | final class Protected { 114 | #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) 115 | private let lock = UnfairLock() 116 | #elseif os(Linux) 117 | private let lock = MutexLock() 118 | #endif 119 | private var value: T 120 | 121 | init(_ value: T) { 122 | self.value = value 123 | } 124 | 125 | /// The contained value. Unsafe for anything more than direct read or write. 126 | var wrappedValue: T { 127 | get { lock.around { value } } 128 | set { lock.around { value = newValue } } 129 | } 130 | 131 | var projectedValue: Protected { self } 132 | 133 | init(wrappedValue: T) { 134 | value = wrappedValue 135 | } 136 | 137 | /// Synchronously read or transform the contained value. 138 | /// 139 | /// - Parameter closure: The closure to execute. 140 | /// 141 | /// - Returns: The return value of the closure passed. 142 | func read(_ closure: (T) -> U) -> U { 143 | lock.around { closure(self.value) } 144 | } 145 | 146 | /// Synchronously modify the protected value. 147 | /// 148 | /// - Parameter closure: The closure to execute. 149 | /// 150 | /// - Returns: The modified value. 151 | @discardableResult 152 | func write(_ closure: (inout T) -> U) -> U { 153 | lock.around { closure(&self.value) } 154 | } 155 | 156 | subscript(dynamicMember keyPath: WritableKeyPath) -> Property { 157 | get { lock.around { value[keyPath: keyPath] } } 158 | set { lock.around { value[keyPath: keyPath] = newValue } } 159 | } 160 | } 161 | 162 | extension Protected where T: RangeReplaceableCollection { 163 | /// Adds a new element to the end of this protected collection. 164 | /// 165 | /// - Parameter newElement: The `Element` to append. 166 | func append(_ newElement: T.Element) { 167 | write { (ward: inout T) in 168 | ward.append(newElement) 169 | } 170 | } 171 | 172 | /// Adds the elements of a sequence to the end of this protected collection. 173 | /// 174 | /// - Parameter newElements: The `Sequence` to append. 175 | func append(contentsOf newElements: S) where S.Element == T.Element { 176 | write { (ward: inout T) in 177 | ward.append(contentsOf: newElements) 178 | } 179 | } 180 | 181 | /// Add the elements of a collection to the end of the protected collection. 182 | /// 183 | /// - Parameter newElements: The `Collection` to append. 184 | func append(contentsOf newElements: C) where C.Element == T.Element { 185 | write { (ward: inout T) in 186 | ward.append(contentsOf: newElements) 187 | } 188 | } 189 | } 190 | 191 | extension Protected where T == Data? { 192 | /// Adds the contents of a `Data` value to the end of the protected `Data`. 193 | /// 194 | /// - Parameter data: The `Data` to be appended. 195 | func append(_ data: Data) { 196 | write { (ward: inout T) in 197 | ward?.append(data) 198 | } 199 | } 200 | } 201 | 202 | extension Protected where T == Request.MutableState { 203 | /// Attempts to transition to the passed `State`. 204 | /// 205 | /// - Parameter state: The `State` to attempt transition to. 206 | /// 207 | /// - Returns: Whether the transition occurred. 208 | func attemptToTransitionTo(_ state: Request.State) -> Bool { 209 | lock.around { 210 | guard value.state.canTransitionTo(state) else { return false } 211 | 212 | value.state = state 213 | 214 | return true 215 | } 216 | } 217 | 218 | /// Perform a closure while locked with the provided `Request.State`. 219 | /// 220 | /// - Parameter perform: The closure to perform while locked. 221 | func withState(perform: (Request.State) -> Void) { 222 | lock.around { perform(value.state) } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/RedirectHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RedirectHandler.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// A type that handles how an HTTP redirect response from a remote server should be redirected to the new request. 28 | public protocol RedirectHandler { 29 | /// Determines how the HTTP redirect response should be redirected to the new request. 30 | /// 31 | /// The `completion` closure should be passed one of three possible options: 32 | /// 33 | /// 1. The new request specified by the redirect (this is the most common use case). 34 | /// 2. A modified version of the new request (you may want to route it somewhere else). 35 | /// 3. A `nil` value to deny the redirect request and return the body of the redirect response. 36 | /// 37 | /// - Parameters: 38 | /// - task: The `URLSessionTask` whose request resulted in a redirect. 39 | /// - request: The `URLRequest` to the new location specified by the redirect response. 40 | /// - response: The `HTTPURLResponse` containing the server's response to the original request. 41 | /// - completion: The closure to execute containing the new `URLRequest`, a modified `URLRequest`, or `nil`. 42 | func task(_ task: URLSessionTask, 43 | willBeRedirectedTo request: URLRequest, 44 | for response: HTTPURLResponse, 45 | completion: @escaping (URLRequest?) -> Void) 46 | } 47 | 48 | // MARK: - 49 | 50 | /// `Redirector` is a convenience `RedirectHandler` making it easy to follow, not follow, or modify a redirect. 51 | public struct Redirector { 52 | /// Defines the behavior of the `Redirector` type. 53 | public enum Behavior { 54 | /// Follow the redirect as defined in the response. 55 | case follow 56 | /// Do not follow the redirect defined in the response. 57 | case doNotFollow 58 | /// Modify the redirect request defined in the response. 59 | case modify((URLSessionTask, URLRequest, HTTPURLResponse) -> URLRequest?) 60 | } 61 | 62 | /// Returns a `Redirector` with a `.follow` `Behavior`. 63 | public static let follow = Redirector(behavior: .follow) 64 | /// Returns a `Redirector` with a `.doNotFollow` `Behavior`. 65 | public static let doNotFollow = Redirector(behavior: .doNotFollow) 66 | 67 | /// The `Behavior` of the `Redirector`. 68 | public let behavior: Behavior 69 | 70 | /// Creates a `Redirector` instance from the `Behavior`. 71 | /// 72 | /// - Parameter behavior: The `Behavior`. 73 | public init(behavior: Behavior) { 74 | self.behavior = behavior 75 | } 76 | } 77 | 78 | // MARK: - 79 | 80 | extension Redirector: RedirectHandler { 81 | public func task(_ task: URLSessionTask, 82 | willBeRedirectedTo request: URLRequest, 83 | for response: HTTPURLResponse, 84 | completion: @escaping (URLRequest?) -> Void) { 85 | switch behavior { 86 | case .follow: 87 | completion(request) 88 | case .doNotFollow: 89 | completion(nil) 90 | case let .modify(closure): 91 | let request = closure(task, request, response) 92 | completion(request) 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/RequestInterceptor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestInterceptor.swift 3 | // 4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// A type that can inspect and optionally adapt a `URLRequest` in some manner if necessary. 28 | public protocol RequestAdapter { 29 | /// Inspects and adapts the specified `URLRequest` in some manner and calls the completion handler with the Result. 30 | /// 31 | /// - Parameters: 32 | /// - urlRequest: The `URLRequest` to adapt. 33 | /// - session: The `Session` that will execute the `URLRequest`. 34 | /// - completion: The completion handler that must be called when adaptation is complete. 35 | func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) 36 | } 37 | 38 | // MARK: - 39 | 40 | /// Outcome of determination whether retry is necessary. 41 | public enum RetryResult { 42 | /// Retry should be attempted immediately. 43 | case retry 44 | /// Retry should be attempted after the associated `TimeInterval`. 45 | case retryWithDelay(TimeInterval) 46 | /// Do not retry. 47 | case doNotRetry 48 | /// Do not retry due to the associated `Error`. 49 | case doNotRetryWithError(Error) 50 | } 51 | 52 | extension RetryResult { 53 | var retryRequired: Bool { 54 | switch self { 55 | case .retry, .retryWithDelay: return true 56 | default: return false 57 | } 58 | } 59 | 60 | var delay: TimeInterval? { 61 | switch self { 62 | case let .retryWithDelay(delay): return delay 63 | default: return nil 64 | } 65 | } 66 | 67 | var error: Error? { 68 | guard case let .doNotRetryWithError(error) = self else { return nil } 69 | return error 70 | } 71 | } 72 | 73 | /// A type that determines whether a request should be retried after being executed by the specified session manager 74 | /// and encountering an error. 75 | public protocol RequestRetrier { 76 | /// Determines whether the `Request` should be retried by calling the `completion` closure. 77 | /// 78 | /// This operation is fully asynchronous. Any amount of time can be taken to determine whether the request needs 79 | /// to be retried. The one requirement is that the completion closure is called to ensure the request is properly 80 | /// cleaned up after. 81 | /// 82 | /// - Parameters: 83 | /// - request: `Request` that failed due to the provided `Error`. 84 | /// - session: `Session` that produced the `Request`. 85 | /// - error: `Error` encountered while executing the `Request`. 86 | /// - completion: Completion closure to be executed when a retry decision has been determined. 87 | func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) 88 | } 89 | 90 | // MARK: - 91 | 92 | /// Type that provides both `RequestAdapter` and `RequestRetrier` functionality. 93 | public protocol RequestInterceptor: RequestAdapter, RequestRetrier {} 94 | 95 | extension RequestInterceptor { 96 | public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { 97 | completion(.success(urlRequest)) 98 | } 99 | 100 | public func retry(_ request: Request, 101 | for session: Session, 102 | dueTo error: Error, 103 | completion: @escaping (RetryResult) -> Void) { 104 | completion(.doNotRetry) 105 | } 106 | } 107 | 108 | /// `RequestAdapter` closure definition. 109 | public typealias AdaptHandler = (URLRequest, Session, _ completion: @escaping (Result) -> Void) -> Void 110 | /// `RequestRetrier` closure definition. 111 | public typealias RetryHandler = (Request, Session, Error, _ completion: @escaping (RetryResult) -> Void) -> Void 112 | 113 | // MARK: - 114 | 115 | /// Closure-based `RequestAdapter`. 116 | open class Adapter: RequestInterceptor { 117 | private let adaptHandler: AdaptHandler 118 | 119 | /// Creates an instance using the provided closure. 120 | /// 121 | /// - Parameter adaptHandler: `AdaptHandler` closure to be executed when handling request adaptation. 122 | public init(_ adaptHandler: @escaping AdaptHandler) { 123 | self.adaptHandler = adaptHandler 124 | } 125 | 126 | open func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { 127 | adaptHandler(urlRequest, session, completion) 128 | } 129 | } 130 | 131 | // MARK: - 132 | 133 | /// Closure-based `RequestRetrier`. 134 | open class Retrier: RequestInterceptor { 135 | private let retryHandler: RetryHandler 136 | 137 | /// Creates an instance using the provided closure. 138 | /// 139 | /// - Parameter retryHandler: `RetryHandler` closure to be executed when handling request retry. 140 | public init(_ retryHandler: @escaping RetryHandler) { 141 | self.retryHandler = retryHandler 142 | } 143 | 144 | open func retry(_ request: Request, 145 | for session: Session, 146 | dueTo error: Error, 147 | completion: @escaping (RetryResult) -> Void) { 148 | retryHandler(request, session, error, completion) 149 | } 150 | } 151 | 152 | // MARK: - 153 | 154 | /// `RequestInterceptor` which can use multiple `RequestAdapter` and `RequestRetrier` values. 155 | open class Interceptor: RequestInterceptor { 156 | /// All `RequestAdapter`s associated with the instance. These adapters will be run until one fails. 157 | public let adapters: [RequestAdapter] 158 | /// All `RequestRetrier`s associated with the instance. These retriers will be run one at a time until one triggers retry. 159 | public let retriers: [RequestRetrier] 160 | 161 | /// Creates an instance from `AdaptHandler` and `RetryHandler` closures. 162 | /// 163 | /// - Parameters: 164 | /// - adaptHandler: `AdaptHandler` closure to be used. 165 | /// - retryHandler: `RetryHandler` closure to be used. 166 | public init(adaptHandler: @escaping AdaptHandler, retryHandler: @escaping RetryHandler) { 167 | adapters = [Adapter(adaptHandler)] 168 | retriers = [Retrier(retryHandler)] 169 | } 170 | 171 | /// Creates an instance from `RequestAdapter` and `RequestRetrier` values. 172 | /// 173 | /// - Parameters: 174 | /// - adapter: `RequestAdapter` value to be used. 175 | /// - retrier: `RequestRetrier` value to be used. 176 | public init(adapter: RequestAdapter, retrier: RequestRetrier) { 177 | adapters = [adapter] 178 | retriers = [retrier] 179 | } 180 | 181 | /// Creates an instance from the arrays of `RequestAdapter` and `RequestRetrier` values. 182 | /// 183 | /// - Parameters: 184 | /// - adapters: `RequestAdapter` values to be used. 185 | /// - retriers: `RequestRetrier` values to be used. 186 | /// - interceptors: `RequestInterceptor`s to be used. 187 | public init(adapters: [RequestAdapter] = [], retriers: [RequestRetrier] = [], interceptors: [RequestInterceptor] = []) { 188 | self.adapters = adapters + interceptors 189 | self.retriers = retriers + interceptors 190 | } 191 | 192 | open func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { 193 | adapt(urlRequest, for: session, using: adapters, completion: completion) 194 | } 195 | 196 | private func adapt(_ urlRequest: URLRequest, 197 | for session: Session, 198 | using adapters: [RequestAdapter], 199 | completion: @escaping (Result) -> Void) { 200 | var pendingAdapters = adapters 201 | 202 | guard !pendingAdapters.isEmpty else { completion(.success(urlRequest)); return } 203 | 204 | let adapter = pendingAdapters.removeFirst() 205 | 206 | adapter.adapt(urlRequest, for: session) { result in 207 | switch result { 208 | case let .success(urlRequest): 209 | self.adapt(urlRequest, for: session, using: pendingAdapters, completion: completion) 210 | case .failure: 211 | completion(result) 212 | } 213 | } 214 | } 215 | 216 | open func retry(_ request: Request, 217 | for session: Session, 218 | dueTo error: Error, 219 | completion: @escaping (RetryResult) -> Void) { 220 | retry(request, for: session, dueTo: error, using: retriers, completion: completion) 221 | } 222 | 223 | private func retry(_ request: Request, 224 | for session: Session, 225 | dueTo error: Error, 226 | using retriers: [RequestRetrier], 227 | completion: @escaping (RetryResult) -> Void) { 228 | var pendingRetriers = retriers 229 | 230 | guard !pendingRetriers.isEmpty else { completion(.doNotRetry); return } 231 | 232 | let retrier = pendingRetriers.removeFirst() 233 | 234 | retrier.retry(request, for: session, dueTo: error) { result in 235 | switch result { 236 | case .retry, .retryWithDelay, .doNotRetryWithError: 237 | completion(result) 238 | case .doNotRetry: 239 | // Only continue to the next retrier if retry was not triggered and no error was encountered 240 | self.retry(request, for: session, dueTo: error, using: pendingRetriers, completion: completion) 241 | } 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/RequestTaskMap.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RequestTaskMap.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// A type that maintains a two way, one to one map of `URLSessionTask`s to `Request`s. 28 | struct RequestTaskMap { 29 | private typealias Events = (completed: Bool, metricsGathered: Bool) 30 | 31 | private var tasksToRequests: [URLSessionTask: Request] 32 | private var requestsToTasks: [Request: URLSessionTask] 33 | private var taskEvents: [URLSessionTask: Events] 34 | 35 | var requests: [Request] { 36 | Array(tasksToRequests.values) 37 | } 38 | 39 | init(tasksToRequests: [URLSessionTask: Request] = [:], 40 | requestsToTasks: [Request: URLSessionTask] = [:], 41 | taskEvents: [URLSessionTask: (completed: Bool, metricsGathered: Bool)] = [:]) { 42 | self.tasksToRequests = tasksToRequests 43 | self.requestsToTasks = requestsToTasks 44 | self.taskEvents = taskEvents 45 | } 46 | 47 | subscript(_ request: Request) -> URLSessionTask? { 48 | get { requestsToTasks[request] } 49 | set { 50 | guard let newValue = newValue else { 51 | guard let task = requestsToTasks[request] else { 52 | fatalError("RequestTaskMap consistency error: no task corresponding to request found.") 53 | } 54 | 55 | requestsToTasks.removeValue(forKey: request) 56 | tasksToRequests.removeValue(forKey: task) 57 | taskEvents.removeValue(forKey: task) 58 | 59 | return 60 | } 61 | 62 | requestsToTasks[request] = newValue 63 | tasksToRequests[newValue] = request 64 | taskEvents[newValue] = (completed: false, metricsGathered: false) 65 | } 66 | } 67 | 68 | subscript(_ task: URLSessionTask) -> Request? { 69 | get { tasksToRequests[task] } 70 | set { 71 | guard let newValue = newValue else { 72 | guard let request = tasksToRequests[task] else { 73 | fatalError("RequestTaskMap consistency error: no request corresponding to task found.") 74 | } 75 | 76 | tasksToRequests.removeValue(forKey: task) 77 | requestsToTasks.removeValue(forKey: request) 78 | taskEvents.removeValue(forKey: task) 79 | 80 | return 81 | } 82 | 83 | tasksToRequests[task] = newValue 84 | requestsToTasks[newValue] = task 85 | taskEvents[task] = (completed: false, metricsGathered: false) 86 | } 87 | } 88 | 89 | var count: Int { 90 | precondition(tasksToRequests.count == requestsToTasks.count, 91 | "RequestTaskMap.count invalid, requests.count: \(tasksToRequests.count) != tasks.count: \(requestsToTasks.count)") 92 | 93 | return tasksToRequests.count 94 | } 95 | 96 | var eventCount: Int { 97 | precondition(taskEvents.count == count, "RequestTaskMap.eventCount invalid, count: \(count) != taskEvents.count: \(taskEvents.count)") 98 | 99 | return taskEvents.count 100 | } 101 | 102 | var isEmpty: Bool { 103 | precondition(tasksToRequests.isEmpty == requestsToTasks.isEmpty, 104 | "RequestTaskMap.isEmpty invalid, requests.isEmpty: \(tasksToRequests.isEmpty) != tasks.isEmpty: \(requestsToTasks.isEmpty)") 105 | 106 | return tasksToRequests.isEmpty 107 | } 108 | 109 | var isEventsEmpty: Bool { 110 | precondition(taskEvents.isEmpty == isEmpty, "RequestTaskMap.isEventsEmpty invalid, isEmpty: \(isEmpty) != taskEvents.isEmpty: \(taskEvents.isEmpty)") 111 | 112 | return taskEvents.isEmpty 113 | } 114 | 115 | mutating func disassociateIfNecessaryAfterGatheringMetricsForTask(_ task: URLSessionTask) -> Bool { 116 | guard let events = taskEvents[task] else { 117 | fatalError("RequestTaskMap consistency error: no events corresponding to task found.") 118 | } 119 | 120 | switch (events.completed, events.metricsGathered) { 121 | case (_, true): fatalError("RequestTaskMap consistency error: duplicate metricsGatheredForTask call.") 122 | case (false, false): taskEvents[task] = (completed: false, metricsGathered: true); return false 123 | case (true, false): self[task] = nil; return true 124 | } 125 | } 126 | 127 | mutating func disassociateIfNecessaryAfterCompletingTask(_ task: URLSessionTask) -> Bool { 128 | guard let events = taskEvents[task] else { 129 | fatalError("RequestTaskMap consistency error: no events corresponding to task found.") 130 | } 131 | 132 | switch (events.completed, events.metricsGathered) { 133 | case (true, _): fatalError("RequestTaskMap consistency error: duplicate completionReceivedForTask call.") 134 | #if os(watchOS) // watchOS doesn't gather metrics, so unconditionally remove the reference and return true. 135 | default: self[task] = nil; return true 136 | #else 137 | case (false, false): taskEvents[task] = (completed: true, metricsGathered: false); return false 138 | case (false, true): self[task] = nil; return true 139 | #endif 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/Result+Alamofire.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Result+Alamofire.swift 3 | // 4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// Default type of `Result` returned by Alamofire, with an `AFError` `Failure` type. 28 | public typealias AFResult = Result 29 | 30 | // MARK: - Internal APIs 31 | 32 | extension Result { 33 | /// Returns whether the instance is `.success`. 34 | var isSuccess: Bool { 35 | guard case .success = self else { return false } 36 | return true 37 | } 38 | 39 | /// Returns whether the instance is `.failure`. 40 | var isFailure: Bool { 41 | !isSuccess 42 | } 43 | 44 | /// Returns the associated value if the result is a success, `nil` otherwise. 45 | var success: Success? { 46 | guard case let .success(value) = self else { return nil } 47 | return value 48 | } 49 | 50 | /// Returns the associated error value if the result is a failure, `nil` otherwise. 51 | var failure: Failure? { 52 | guard case let .failure(error) = self else { return nil } 53 | return error 54 | } 55 | 56 | /// Initializes a `Result` from value or error. Returns `.failure` if the error is non-nil, `.success` otherwise. 57 | /// 58 | /// - Parameters: 59 | /// - value: A value. 60 | /// - error: An `Error`. 61 | init(value: Success, error: Failure?) { 62 | if let error = error { 63 | self = .failure(error) 64 | } else { 65 | self = .success(value) 66 | } 67 | } 68 | 69 | /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter. 70 | /// 71 | /// Use the `tryMap` method with a closure that may throw an error. For example: 72 | /// 73 | /// let possibleData: Result = .success(Data(...)) 74 | /// let possibleObject = possibleData.tryMap { 75 | /// try JSONSerialization.jsonObject(with: $0) 76 | /// } 77 | /// 78 | /// - parameter transform: A closure that takes the success value of the instance. 79 | /// 80 | /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the 81 | /// same failure. 82 | func tryMap(_ transform: (Success) throws -> NewSuccess) -> Result { 83 | switch self { 84 | case let .success(value): 85 | do { 86 | return try .success(transform(value)) 87 | } catch { 88 | return .failure(error) 89 | } 90 | case let .failure(error): 91 | return .failure(error) 92 | } 93 | } 94 | 95 | /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter. 96 | /// 97 | /// Use the `tryMapError` function with a closure that may throw an error. For example: 98 | /// 99 | /// let possibleData: Result = .success(Data(...)) 100 | /// let possibleObject = possibleData.tryMapError { 101 | /// try someFailableFunction(taking: $0) 102 | /// } 103 | /// 104 | /// - Parameter transform: A throwing closure that takes the error of the instance. 105 | /// 106 | /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns 107 | /// the same success. 108 | func tryMapError(_ transform: (Failure) throws -> NewFailure) -> Result { 109 | switch self { 110 | case let .failure(error): 111 | do { 112 | return try .failure(transform(error)) 113 | } catch { 114 | return .failure(error) 115 | } 116 | case let .success(value): 117 | return .success(value) 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/SessionDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SessionDelegate.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// Class which implements the various `URLSessionDelegate` methods to connect various Alamofire features. 28 | open class SessionDelegate: NSObject { 29 | private let fileManager: FileManager 30 | 31 | weak var stateProvider: SessionStateProvider? 32 | var eventMonitor: EventMonitor? 33 | 34 | /// Creates an instance from the given `FileManager`. 35 | /// 36 | /// - Parameter fileManager: `FileManager` to use for underlying file management, such as moving downloaded files. 37 | /// `.default` by default. 38 | public init(fileManager: FileManager = .default) { 39 | self.fileManager = fileManager 40 | } 41 | 42 | /// Internal method to find and cast requests while maintaining some integrity checking. 43 | /// 44 | /// - Parameters: 45 | /// - task: The `URLSessionTask` for which to find the associated `Request`. 46 | /// - type: The `Request` subclass type to cast any `Request` associate with `task`. 47 | func request(for task: URLSessionTask, as type: R.Type) -> R? { 48 | guard let provider = stateProvider else { 49 | assertionFailure("StateProvider is nil.") 50 | return nil 51 | } 52 | 53 | return provider.request(for: task) as? R 54 | } 55 | } 56 | 57 | /// Type which provides various `Session` state values. 58 | protocol SessionStateProvider: AnyObject { 59 | var serverTrustManager: ServerTrustManager? { get } 60 | var redirectHandler: RedirectHandler? { get } 61 | var cachedResponseHandler: CachedResponseHandler? { get } 62 | 63 | func request(for task: URLSessionTask) -> Request? 64 | func didGatherMetricsForTask(_ task: URLSessionTask) 65 | func didCompleteTask(_ task: URLSessionTask, completion: @escaping () -> Void) 66 | func credential(for task: URLSessionTask, in protectionSpace: URLProtectionSpace) -> URLCredential? 67 | func cancelRequestsForSessionInvalidation(with error: Error?) 68 | } 69 | 70 | // MARK: URLSessionDelegate 71 | 72 | extension SessionDelegate: URLSessionDelegate { 73 | open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) { 74 | eventMonitor?.urlSession(session, didBecomeInvalidWithError: error) 75 | 76 | stateProvider?.cancelRequestsForSessionInvalidation(with: error) 77 | } 78 | } 79 | 80 | // MARK: URLSessionTaskDelegate 81 | 82 | extension SessionDelegate: URLSessionTaskDelegate { 83 | /// Result of a `URLAuthenticationChallenge` evaluation. 84 | typealias ChallengeEvaluation = (disposition: URLSession.AuthChallengeDisposition, credential: URLCredential?, error: AFError?) 85 | 86 | open func urlSession(_ session: URLSession, 87 | task: URLSessionTask, 88 | didReceive challenge: URLAuthenticationChallenge, 89 | completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { 90 | eventMonitor?.urlSession(session, task: task, didReceive: challenge) 91 | 92 | let evaluation: ChallengeEvaluation 93 | switch challenge.protectionSpace.authenticationMethod { 94 | case NSURLAuthenticationMethodServerTrust: 95 | evaluation = attemptServerTrustAuthentication(with: challenge) 96 | case NSURLAuthenticationMethodHTTPBasic, NSURLAuthenticationMethodHTTPDigest, NSURLAuthenticationMethodNTLM, 97 | NSURLAuthenticationMethodNegotiate, NSURLAuthenticationMethodClientCertificate: 98 | evaluation = attemptCredentialAuthentication(for: challenge, belongingTo: task) 99 | default: 100 | evaluation = (.performDefaultHandling, nil, nil) 101 | } 102 | 103 | if let error = evaluation.error { 104 | stateProvider?.request(for: task)?.didFailTask(task, earlyWithError: error) 105 | } 106 | 107 | completionHandler(evaluation.disposition, evaluation.credential) 108 | } 109 | 110 | /// Evaluates the server trust `URLAuthenticationChallenge` received. 111 | /// 112 | /// - Parameter challenge: The `URLAuthenticationChallenge`. 113 | /// 114 | /// - Returns: The `ChallengeEvaluation`. 115 | func attemptServerTrustAuthentication(with challenge: URLAuthenticationChallenge) -> ChallengeEvaluation { 116 | let host = challenge.protectionSpace.host 117 | 118 | guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust, 119 | let trust = challenge.protectionSpace.serverTrust 120 | else { 121 | return (.performDefaultHandling, nil, nil) 122 | } 123 | 124 | do { 125 | guard let evaluator = try stateProvider?.serverTrustManager?.serverTrustEvaluator(forHost: host) else { 126 | return (.performDefaultHandling, nil, nil) 127 | } 128 | 129 | try evaluator.evaluate(trust, forHost: host) 130 | 131 | return (.useCredential, URLCredential(trust: trust), nil) 132 | } catch { 133 | return (.cancelAuthenticationChallenge, nil, error.asAFError(or: .serverTrustEvaluationFailed(reason: .customEvaluationFailed(error: error)))) 134 | } 135 | } 136 | 137 | /// Evaluates the credential-based authentication `URLAuthenticationChallenge` received for `task`. 138 | /// 139 | /// - Parameters: 140 | /// - challenge: The `URLAuthenticationChallenge`. 141 | /// - task: The `URLSessionTask` which received the challenge. 142 | /// 143 | /// - Returns: The `ChallengeEvaluation`. 144 | func attemptCredentialAuthentication(for challenge: URLAuthenticationChallenge, 145 | belongingTo task: URLSessionTask) -> ChallengeEvaluation { 146 | guard challenge.previousFailureCount == 0 else { 147 | return (.rejectProtectionSpace, nil, nil) 148 | } 149 | 150 | guard let credential = stateProvider?.credential(for: task, in: challenge.protectionSpace) else { 151 | return (.performDefaultHandling, nil, nil) 152 | } 153 | 154 | return (.useCredential, credential, nil) 155 | } 156 | 157 | open func urlSession(_ session: URLSession, 158 | task: URLSessionTask, 159 | didSendBodyData bytesSent: Int64, 160 | totalBytesSent: Int64, 161 | totalBytesExpectedToSend: Int64) { 162 | eventMonitor?.urlSession(session, 163 | task: task, 164 | didSendBodyData: bytesSent, 165 | totalBytesSent: totalBytesSent, 166 | totalBytesExpectedToSend: totalBytesExpectedToSend) 167 | 168 | stateProvider?.request(for: task)?.updateUploadProgress(totalBytesSent: totalBytesSent, 169 | totalBytesExpectedToSend: totalBytesExpectedToSend) 170 | } 171 | 172 | open func urlSession(_ session: URLSession, 173 | task: URLSessionTask, 174 | needNewBodyStream completionHandler: @escaping (InputStream?) -> Void) { 175 | eventMonitor?.urlSession(session, taskNeedsNewBodyStream: task) 176 | 177 | guard let request = request(for: task, as: UploadRequest.self) else { 178 | assertionFailure("needNewBodyStream did not find UploadRequest.") 179 | completionHandler(nil) 180 | return 181 | } 182 | 183 | completionHandler(request.inputStream()) 184 | } 185 | 186 | open func urlSession(_ session: URLSession, 187 | task: URLSessionTask, 188 | willPerformHTTPRedirection response: HTTPURLResponse, 189 | newRequest request: URLRequest, 190 | completionHandler: @escaping (URLRequest?) -> Void) { 191 | eventMonitor?.urlSession(session, task: task, willPerformHTTPRedirection: response, newRequest: request) 192 | 193 | if let redirectHandler = stateProvider?.request(for: task)?.redirectHandler ?? stateProvider?.redirectHandler { 194 | redirectHandler.task(task, willBeRedirectedTo: request, for: response, completion: completionHandler) 195 | } else { 196 | completionHandler(request) 197 | } 198 | } 199 | 200 | open func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) { 201 | eventMonitor?.urlSession(session, task: task, didFinishCollecting: metrics) 202 | 203 | stateProvider?.request(for: task)?.didGatherMetrics(metrics) 204 | 205 | stateProvider?.didGatherMetricsForTask(task) 206 | } 207 | 208 | open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { 209 | eventMonitor?.urlSession(session, task: task, didCompleteWithError: error) 210 | 211 | let request = stateProvider?.request(for: task) 212 | 213 | stateProvider?.didCompleteTask(task) { 214 | request?.didCompleteTask(task, with: error.map { $0.asAFError(or: .sessionTaskFailed(error: $0)) }) 215 | } 216 | } 217 | 218 | @available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) 219 | open func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) { 220 | eventMonitor?.urlSession(session, taskIsWaitingForConnectivity: task) 221 | } 222 | } 223 | 224 | // MARK: URLSessionDataDelegate 225 | 226 | extension SessionDelegate: URLSessionDataDelegate { 227 | open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { 228 | eventMonitor?.urlSession(session, dataTask: dataTask, didReceive: data) 229 | 230 | if let request = request(for: dataTask, as: DataRequest.self) { 231 | request.didReceive(data: data) 232 | } else if let request = request(for: dataTask, as: DataStreamRequest.self) { 233 | request.didReceive(data: data) 234 | } else { 235 | assertionFailure("dataTask did not find DataRequest or DataStreamRequest in didReceive") 236 | return 237 | } 238 | } 239 | 240 | open func urlSession(_ session: URLSession, 241 | dataTask: URLSessionDataTask, 242 | willCacheResponse proposedResponse: CachedURLResponse, 243 | completionHandler: @escaping (CachedURLResponse?) -> Void) { 244 | eventMonitor?.urlSession(session, dataTask: dataTask, willCacheResponse: proposedResponse) 245 | 246 | if let handler = stateProvider?.request(for: dataTask)?.cachedResponseHandler ?? stateProvider?.cachedResponseHandler { 247 | handler.dataTask(dataTask, willCacheResponse: proposedResponse, completion: completionHandler) 248 | } else { 249 | completionHandler(proposedResponse) 250 | } 251 | } 252 | } 253 | 254 | // MARK: URLSessionDownloadDelegate 255 | 256 | extension SessionDelegate: URLSessionDownloadDelegate { 257 | open func urlSession(_ session: URLSession, 258 | downloadTask: URLSessionDownloadTask, 259 | didResumeAtOffset fileOffset: Int64, 260 | expectedTotalBytes: Int64) { 261 | eventMonitor?.urlSession(session, 262 | downloadTask: downloadTask, 263 | didResumeAtOffset: fileOffset, 264 | expectedTotalBytes: expectedTotalBytes) 265 | guard let downloadRequest = request(for: downloadTask, as: DownloadRequest.self) else { 266 | assertionFailure("downloadTask did not find DownloadRequest.") 267 | return 268 | } 269 | 270 | downloadRequest.updateDownloadProgress(bytesWritten: fileOffset, 271 | totalBytesExpectedToWrite: expectedTotalBytes) 272 | } 273 | 274 | open func urlSession(_ session: URLSession, 275 | downloadTask: URLSessionDownloadTask, 276 | didWriteData bytesWritten: Int64, 277 | totalBytesWritten: Int64, 278 | totalBytesExpectedToWrite: Int64) { 279 | eventMonitor?.urlSession(session, 280 | downloadTask: downloadTask, 281 | didWriteData: bytesWritten, 282 | totalBytesWritten: totalBytesWritten, 283 | totalBytesExpectedToWrite: totalBytesExpectedToWrite) 284 | guard let downloadRequest = request(for: downloadTask, as: DownloadRequest.self) else { 285 | assertionFailure("downloadTask did not find DownloadRequest.") 286 | return 287 | } 288 | 289 | downloadRequest.updateDownloadProgress(bytesWritten: bytesWritten, 290 | totalBytesExpectedToWrite: totalBytesExpectedToWrite) 291 | } 292 | 293 | open func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { 294 | eventMonitor?.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location) 295 | 296 | guard let request = request(for: downloadTask, as: DownloadRequest.self) else { 297 | assertionFailure("downloadTask did not find DownloadRequest.") 298 | return 299 | } 300 | 301 | guard let response = request.response else { 302 | fatalError("URLSessionDownloadTask finished downloading with no response.") 303 | } 304 | 305 | let (destination, options) = (request.destination)(location, response) 306 | 307 | eventMonitor?.request(request, didCreateDestinationURL: destination) 308 | 309 | do { 310 | if options.contains(.removePreviousFile), fileManager.fileExists(atPath: destination.path) { 311 | try fileManager.removeItem(at: destination) 312 | } 313 | 314 | if options.contains(.createIntermediateDirectories) { 315 | let directory = destination.deletingLastPathComponent() 316 | try fileManager.createDirectory(at: directory, withIntermediateDirectories: true) 317 | } 318 | 319 | try fileManager.moveItem(at: location, to: destination) 320 | 321 | request.didFinishDownloading(using: downloadTask, with: .success(destination)) 322 | } catch { 323 | request.didFinishDownloading(using: downloadTask, with: .failure(.downloadedFileMoveFailed(error: error, 324 | source: location, 325 | destination: destination))) 326 | } 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/StringEncoding+Alamofire.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringEncoding+Alamofire.swift 3 | // 4 | // Copyright (c) 2020 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | extension String.Encoding { 28 | /// Creates an encoding from the IANA charset name. 29 | /// 30 | /// - Notes: These mappings match those [provided by CoreFoundation](https://opensource.apple.com/source/CF/CF-476.18/CFStringUtilities.c.auto.html) 31 | /// 32 | /// - Parameter name: IANA charset name. 33 | init?(ianaCharsetName name: String) { 34 | switch name.lowercased() { 35 | case "utf-8": 36 | self = .utf8 37 | case "iso-8859-1": 38 | self = .isoLatin1 39 | case "unicode-1-1", "iso-10646-ucs-2", "utf-16": 40 | self = .utf16 41 | case "utf-16be": 42 | self = .utf16BigEndian 43 | case "utf-16le": 44 | self = .utf16LittleEndian 45 | case "utf-32": 46 | self = .utf32 47 | case "utf-32be": 48 | self = .utf32BigEndian 49 | case "utf-32le": 50 | self = .utf32LittleEndian 51 | default: 52 | return nil 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/URLConvertible+URLRequestConvertible.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLConvertible+URLRequestConvertible.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | /// Types adopting the `URLConvertible` protocol can be used to construct `URL`s, which can then be used to construct 28 | /// `URLRequests`. 29 | public protocol URLConvertible { 30 | /// Returns a `URL` from the conforming instance or throws. 31 | /// 32 | /// - Returns: The `URL` created from the instance. 33 | /// - Throws: Any error thrown while creating the `URL`. 34 | func asURL() throws -> URL 35 | } 36 | 37 | extension String: URLConvertible { 38 | /// Returns a `URL` if `self` can be used to initialize a `URL` instance, otherwise throws. 39 | /// 40 | /// - Returns: The `URL` initialized with `self`. 41 | /// - Throws: An `AFError.invalidURL` instance. 42 | public func asURL() throws -> URL { 43 | guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) } 44 | 45 | return url 46 | } 47 | } 48 | 49 | extension URL: URLConvertible { 50 | /// Returns `self`. 51 | public func asURL() throws -> URL { self } 52 | } 53 | 54 | extension URLComponents: URLConvertible { 55 | /// Returns a `URL` if the `self`'s `url` is not nil, otherwise throws. 56 | /// 57 | /// - Returns: The `URL` from the `url` property. 58 | /// - Throws: An `AFError.invalidURL` instance. 59 | public func asURL() throws -> URL { 60 | guard let url = url else { throw AFError.invalidURL(url: self) } 61 | 62 | return url 63 | } 64 | } 65 | 66 | // MARK: - 67 | 68 | /// Types adopting the `URLRequestConvertible` protocol can be used to safely construct `URLRequest`s. 69 | public protocol URLRequestConvertible { 70 | /// Returns a `URLRequest` or throws if an `Error` was encountered. 71 | /// 72 | /// - Returns: A `URLRequest`. 73 | /// - Throws: Any error thrown while constructing the `URLRequest`. 74 | func asURLRequest() throws -> URLRequest 75 | } 76 | 77 | extension URLRequestConvertible { 78 | /// The `URLRequest` returned by discarding any `Error` encountered. 79 | public var urlRequest: URLRequest? { try? asURLRequest() } 80 | } 81 | 82 | extension URLRequest: URLRequestConvertible { 83 | /// Returns `self`. 84 | public func asURLRequest() throws -> URLRequest { self } 85 | } 86 | 87 | // MARK: - 88 | 89 | extension URLRequest { 90 | /// Creates an instance with the specified `url`, `method`, and `headers`. 91 | /// 92 | /// - Parameters: 93 | /// - url: The `URLConvertible` value. 94 | /// - method: The `HTTPMethod`. 95 | /// - headers: The `HTTPHeaders`, `nil` by default. 96 | /// - Throws: Any error thrown while converting the `URLConvertible` to a `URL`. 97 | public init(url: URLConvertible, method: HTTPMethod, headers: HTTPHeaders? = nil) throws { 98 | let url = try url.asURL() 99 | 100 | self.init(url: url) 101 | 102 | httpMethod = method.rawValue 103 | allHTTPHeaderFields = headers?.dictionary 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/URLRequest+Alamofire.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLRequest+Alamofire.swift 3 | // 4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | public extension URLRequest { 28 | /// Returns the `httpMethod` as Alamofire's `HTTPMethod` type. 29 | var method: HTTPMethod? { 30 | get { httpMethod.flatMap(HTTPMethod.init) } 31 | set { httpMethod = newValue?.rawValue } 32 | } 33 | 34 | func validate() throws { 35 | if method == .get, let bodyData = httpBody { 36 | throw AFError.urlRequestValidationFailed(reason: .bodyDataInGETRequest(bodyData)) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/URLSessionConfiguration+Alamofire.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLSessionConfiguration+Alamofire.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | extension URLSessionConfiguration: AlamofireExtended {} 28 | extension AlamofireExtension where ExtendedType: URLSessionConfiguration { 29 | /// Alamofire's default configuration. Same as `URLSessionConfiguration.default` but adds Alamofire default 30 | /// `Accept-Language`, `Accept-Encoding`, and `User-Agent` headers. 31 | public static var `default`: URLSessionConfiguration { 32 | let configuration = URLSessionConfiguration.default 33 | configuration.headers = .default 34 | 35 | return configuration 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Pods/Alamofire/Source/Validation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Validation.swift 3 | // 4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/) 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | // 24 | 25 | import Foundation 26 | 27 | extension Request { 28 | // MARK: Helper Types 29 | 30 | fileprivate typealias ErrorReason = AFError.ResponseValidationFailureReason 31 | 32 | /// Used to represent whether a validation succeeded or failed. 33 | public typealias ValidationResult = Result 34 | 35 | fileprivate struct MIMEType { 36 | let type: String 37 | let subtype: String 38 | 39 | var isWildcard: Bool { type == "*" && subtype == "*" } 40 | 41 | init?(_ string: String) { 42 | let components: [String] = { 43 | let stripped = string.trimmingCharacters(in: .whitespacesAndNewlines) 44 | let split = stripped[..<(stripped.range(of: ";")?.lowerBound ?? stripped.endIndex)] 45 | 46 | return split.components(separatedBy: "/") 47 | }() 48 | 49 | if let type = components.first, let subtype = components.last { 50 | self.type = type 51 | self.subtype = subtype 52 | } else { 53 | return nil 54 | } 55 | } 56 | 57 | func matches(_ mime: MIMEType) -> Bool { 58 | switch (type, subtype) { 59 | case (mime.type, mime.subtype), (mime.type, "*"), ("*", mime.subtype), ("*", "*"): 60 | return true 61 | default: 62 | return false 63 | } 64 | } 65 | } 66 | 67 | // MARK: Properties 68 | 69 | fileprivate var acceptableStatusCodes: Range { 200..<300 } 70 | 71 | fileprivate var acceptableContentTypes: [String] { 72 | if let accept = request?.value(forHTTPHeaderField: "Accept") { 73 | return accept.components(separatedBy: ",") 74 | } 75 | 76 | return ["*/*"] 77 | } 78 | 79 | // MARK: Status Code 80 | 81 | fileprivate func validate(statusCode acceptableStatusCodes: S, 82 | response: HTTPURLResponse) 83 | -> ValidationResult 84 | where S.Iterator.Element == Int { 85 | if acceptableStatusCodes.contains(response.statusCode) { 86 | return .success(Void()) 87 | } else { 88 | let reason: ErrorReason = .unacceptableStatusCode(code: response.statusCode) 89 | return .failure(AFError.responseValidationFailed(reason: reason)) 90 | } 91 | } 92 | 93 | // MARK: Content Type 94 | 95 | fileprivate func validate(contentType acceptableContentTypes: S, 96 | response: HTTPURLResponse, 97 | data: Data?) 98 | -> ValidationResult 99 | where S.Iterator.Element == String { 100 | guard let data = data, !data.isEmpty else { return .success(Void()) } 101 | 102 | return validate(contentType: acceptableContentTypes, response: response) 103 | } 104 | 105 | fileprivate func validate(contentType acceptableContentTypes: S, 106 | response: HTTPURLResponse) 107 | -> ValidationResult 108 | where S.Iterator.Element == String { 109 | guard 110 | let responseContentType = response.mimeType, 111 | let responseMIMEType = MIMEType(responseContentType) 112 | else { 113 | for contentType in acceptableContentTypes { 114 | if let mimeType = MIMEType(contentType), mimeType.isWildcard { 115 | return .success(Void()) 116 | } 117 | } 118 | 119 | let error: AFError = { 120 | let reason: ErrorReason = .missingContentType(acceptableContentTypes: Array(acceptableContentTypes)) 121 | return AFError.responseValidationFailed(reason: reason) 122 | }() 123 | 124 | return .failure(error) 125 | } 126 | 127 | for contentType in acceptableContentTypes { 128 | if let acceptableMIMEType = MIMEType(contentType), acceptableMIMEType.matches(responseMIMEType) { 129 | return .success(Void()) 130 | } 131 | } 132 | 133 | let error: AFError = { 134 | let reason: ErrorReason = .unacceptableContentType(acceptableContentTypes: Array(acceptableContentTypes), 135 | responseContentType: responseContentType) 136 | 137 | return AFError.responseValidationFailed(reason: reason) 138 | }() 139 | 140 | return .failure(error) 141 | } 142 | } 143 | 144 | // MARK: - 145 | 146 | extension DataRequest { 147 | /// A closure used to validate a request that takes a URL request, a URL response and data, and returns whether the 148 | /// request was valid. 149 | public typealias Validation = (URLRequest?, HTTPURLResponse, Data?) -> ValidationResult 150 | 151 | /// Validates that the response has a status code in the specified sequence. 152 | /// 153 | /// If validation fails, subsequent calls to response handlers will have an associated error. 154 | /// 155 | /// - Parameter statusCode: `Sequence` of acceptable response status codes. 156 | /// 157 | /// - Returns: The instance. 158 | @discardableResult 159 | public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int { 160 | return validate { [unowned self] _, response, _ in 161 | self.validate(statusCode: acceptableStatusCodes, response: response) 162 | } 163 | } 164 | 165 | /// Validates that the response has a content type in the specified sequence. 166 | /// 167 | /// If validation fails, subsequent calls to response handlers will have an associated error. 168 | /// 169 | /// - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes. 170 | /// 171 | /// - returns: The request. 172 | @discardableResult 173 | public func validate(contentType acceptableContentTypes: @escaping @autoclosure () -> S) -> Self where S.Iterator.Element == String { 174 | return validate { [unowned self] _, response, data in 175 | self.validate(contentType: acceptableContentTypes(), response: response, data: data) 176 | } 177 | } 178 | 179 | /// Validates that the response has a status code in the default acceptable range of 200...299, and that the content 180 | /// type matches any specified in the Accept HTTP header field. 181 | /// 182 | /// If validation fails, subsequent calls to response handlers will have an associated error. 183 | /// 184 | /// - returns: The request. 185 | @discardableResult 186 | public func validate() -> Self { 187 | let contentTypes: () -> [String] = { [unowned self] in 188 | self.acceptableContentTypes 189 | } 190 | return validate(statusCode: acceptableStatusCodes).validate(contentType: contentTypes()) 191 | } 192 | } 193 | 194 | extension DataStreamRequest { 195 | /// A closure used to validate a request that takes a `URLRequest` and `HTTPURLResponse` and returns whether the 196 | /// request was valid. 197 | public typealias Validation = (_ request: URLRequest?, _ response: HTTPURLResponse) -> ValidationResult 198 | 199 | /// Validates that the response has a status code in the specified sequence. 200 | /// 201 | /// If validation fails, subsequent calls to response handlers will have an associated error. 202 | /// 203 | /// - Parameter statusCode: `Sequence` of acceptable response status codes. 204 | /// 205 | /// - Returns: The instance. 206 | @discardableResult 207 | public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int { 208 | return validate { [unowned self] _, response in 209 | self.validate(statusCode: acceptableStatusCodes, response: response) 210 | } 211 | } 212 | 213 | /// Validates that the response has a content type in the specified sequence. 214 | /// 215 | /// If validation fails, subsequent calls to response handlers will have an associated error. 216 | /// 217 | /// - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes. 218 | /// 219 | /// - returns: The request. 220 | @discardableResult 221 | public func validate(contentType acceptableContentTypes: @escaping @autoclosure () -> S) -> Self where S.Iterator.Element == String { 222 | return validate { [unowned self] _, response in 223 | self.validate(contentType: acceptableContentTypes(), response: response) 224 | } 225 | } 226 | 227 | /// Validates that the response has a status code in the default acceptable range of 200...299, and that the content 228 | /// type matches any specified in the Accept HTTP header field. 229 | /// 230 | /// If validation fails, subsequent calls to response handlers will have an associated error. 231 | /// 232 | /// - Returns: The instance. 233 | @discardableResult 234 | public func validate() -> Self { 235 | validate(statusCode: acceptableStatusCodes).validate(contentType: self.acceptableContentTypes) 236 | } 237 | } 238 | 239 | // MARK: - 240 | 241 | extension DownloadRequest { 242 | /// A closure used to validate a request that takes a URL request, a URL response, a temporary URL and a 243 | /// destination URL, and returns whether the request was valid. 244 | public typealias Validation = (_ request: URLRequest?, 245 | _ response: HTTPURLResponse, 246 | _ fileURL: URL?) 247 | -> ValidationResult 248 | 249 | /// Validates that the response has a status code in the specified sequence. 250 | /// 251 | /// If validation fails, subsequent calls to response handlers will have an associated error. 252 | /// 253 | /// - Parameter statusCode: `Sequence` of acceptable response status codes. 254 | /// 255 | /// - Returns: The instance. 256 | @discardableResult 257 | public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int { 258 | return validate { [unowned self] _, response, _ in 259 | self.validate(statusCode: acceptableStatusCodes, response: response) 260 | } 261 | } 262 | 263 | /// Validates that the response has a content type in the specified sequence. 264 | /// 265 | /// If validation fails, subsequent calls to response handlers will have an associated error. 266 | /// 267 | /// - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes. 268 | /// 269 | /// - returns: The request. 270 | @discardableResult 271 | public func validate(contentType acceptableContentTypes: @escaping @autoclosure () -> S) -> Self where S.Iterator.Element == String { 272 | return validate { [unowned self] _, response, fileURL in 273 | guard let validFileURL = fileURL else { 274 | return .failure(AFError.responseValidationFailed(reason: .dataFileNil)) 275 | } 276 | 277 | do { 278 | let data = try Data(contentsOf: validFileURL) 279 | return self.validate(contentType: acceptableContentTypes(), response: response, data: data) 280 | } catch { 281 | return .failure(AFError.responseValidationFailed(reason: .dataFileReadFailed(at: validFileURL))) 282 | } 283 | } 284 | } 285 | 286 | /// Validates that the response has a status code in the default acceptable range of 200...299, and that the content 287 | /// type matches any specified in the Accept HTTP header field. 288 | /// 289 | /// If validation fails, subsequent calls to response handlers will have an associated error. 290 | /// 291 | /// - returns: The request. 292 | @discardableResult 293 | public func validate() -> Self { 294 | let contentTypes = { [unowned self] in 295 | self.acceptableContentTypes 296 | } 297 | return validate(statusCode: acceptableStatusCodes).validate(contentType: contentTypes()) 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (5.2.0) 3 | 4 | DEPENDENCIES: 5 | - Alamofire (~> 5.2) 6 | 7 | SPEC REPOS: 8 | trunk: 9 | - Alamofire 10 | 11 | SPEC CHECKSUMS: 12 | Alamofire: c1ca147559e730bfb2182c8c7aafbdd90a867987 13 | 14 | PODFILE CHECKSUM: ffed80872d7a5ffe5c808454d9d57660affb875f 15 | 16 | COCOAPODS: 1.9.1 17 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/omarmhaimdat.xcuserdatad/xcschemes/Alamofire.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/omarmhaimdat.xcuserdatad/xcschemes/Pods-segmentation_api.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/omarmhaimdat.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Alamofire.xcscheme 8 | 9 | isShown 10 | 11 | orderHint 12 | 0 13 | 14 | Pods-segmentation_api.xcscheme 15 | 16 | isShown 17 | 18 | orderHint 19 | 1 20 | 21 | 22 | SuppressBuildableAutocreation 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 5.2.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Alamofire : NSObject 3 | @end 4 | @implementation PodsDummy_Alamofire 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double AlamofireVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char AlamofireVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" 4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire.modulemap: -------------------------------------------------------------------------------- 1 | framework module Alamofire { 2 | umbrella header "Alamofire-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Alamofire/Alamofire.release.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" 4 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## Alamofire 5 | 6 | Copyright (c) 2014-2020 Alamofire Software Foundation (http://alamofire.org/) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2014-2020 Alamofire Software Foundation (http://alamofire.org/) 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | Alamofire 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_segmentation_api : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_segmentation_api 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | 23 | # Used as a return value for each invocation of `strip_invalid_archs` function. 24 | STRIP_BINARY_RETVAL=0 25 | 26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 29 | 30 | # Copies and strips a vendored framework 31 | install_framework() 32 | { 33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 34 | local source="${BUILT_PRODUCTS_DIR}/$1" 35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 37 | elif [ -r "$1" ]; then 38 | local source="$1" 39 | fi 40 | 41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 42 | 43 | if [ -L "${source}" ]; then 44 | echo "Symlinked..." 45 | source="$(readlink "${source}")" 46 | fi 47 | 48 | # Use filter instead of exclude so missing patterns don't throw errors. 49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 51 | 52 | local basename 53 | basename="$(basename -s .framework "$1")" 54 | binary="${destination}/${basename}.framework/${basename}" 55 | 56 | if ! [ -r "$binary" ]; then 57 | binary="${destination}/${basename}" 58 | elif [ -L "${binary}" ]; then 59 | echo "Destination binary is symlinked..." 60 | dirname="$(dirname "${binary}")" 61 | binary="${dirname}/$(readlink "${binary}")" 62 | fi 63 | 64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 66 | strip_invalid_archs "$binary" 67 | fi 68 | 69 | # Resign the code if required by the build settings to avoid unstable apps 70 | code_sign_if_enabled "${destination}/$(basename "$1")" 71 | 72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 74 | local swift_runtime_libs 75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 76 | for lib in $swift_runtime_libs; do 77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 79 | code_sign_if_enabled "${destination}/${lib}" 80 | done 81 | fi 82 | } 83 | 84 | # Copies and strips a vendored dSYM 85 | install_dsym() { 86 | local source="$1" 87 | warn_missing_arch=${2:-true} 88 | if [ -r "$source" ]; then 89 | # Copy the dSYM into the targets temp dir. 90 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 91 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 92 | 93 | local basename 94 | basename="$(basename -s .dSYM "$source")" 95 | binary_name="$(ls "$source/Contents/Resources/DWARF")" 96 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" 97 | 98 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 99 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then 100 | strip_invalid_archs "$binary" "$warn_missing_arch" 101 | fi 102 | 103 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 104 | # Move the stripped file into its final destination. 105 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 106 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 107 | else 108 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 109 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" 110 | fi 111 | fi 112 | } 113 | 114 | # Copies the bcsymbolmap files of a vendored framework 115 | install_bcsymbolmap() { 116 | local bcsymbolmap_path="$1" 117 | local destination="${BUILT_PRODUCTS_DIR}" 118 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" 119 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" 120 | } 121 | 122 | # Signs a framework with the provided identity 123 | code_sign_if_enabled() { 124 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 125 | # Use the current code_sign_identity 126 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 127 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 128 | 129 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 130 | code_sign_cmd="$code_sign_cmd &" 131 | fi 132 | echo "$code_sign_cmd" 133 | eval "$code_sign_cmd" 134 | fi 135 | } 136 | 137 | # Strip invalid architectures 138 | strip_invalid_archs() { 139 | binary="$1" 140 | warn_missing_arch=${2:-true} 141 | # Get architectures for current target binary 142 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 143 | # Intersect them with the architectures we are building for 144 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 145 | # If there are no archs supported by this binary then warn the user 146 | if [[ -z "$intersected_archs" ]]; then 147 | if [[ "$warn_missing_arch" == "true" ]]; then 148 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 149 | fi 150 | STRIP_BINARY_RETVAL=0 151 | return 152 | fi 153 | stripped="" 154 | for arch in $binary_archs; do 155 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 156 | # Strip non-valid architectures in-place 157 | lipo -remove "$arch" -output "$binary" "$binary" 158 | stripped="$stripped $arch" 159 | fi 160 | done 161 | if [[ "$stripped" ]]; then 162 | echo "Stripped $binary of architectures:$stripped" 163 | fi 164 | STRIP_BINARY_RETVAL=1 165 | } 166 | 167 | install_artifact() { 168 | artifact="$1" 169 | base="$(basename "$artifact")" 170 | case $base in 171 | *.framework) 172 | install_framework "$artifact" 173 | ;; 174 | *.dSYM) 175 | # Suppress arch warnings since XCFrameworks will include many dSYM files 176 | install_dsym "$artifact" "false" 177 | ;; 178 | *.bcsymbolmap) 179 | install_bcsymbolmap "$artifact" 180 | ;; 181 | *) 182 | echo "error: Unrecognized artifact "$artifact"" 183 | ;; 184 | esac 185 | } 186 | 187 | copy_artifacts() { 188 | file_list="$1" 189 | while read artifact; do 190 | install_artifact "$artifact" 191 | done <$file_list 192 | } 193 | 194 | ARTIFACT_LIST_FILE="${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt" 195 | if [ -r "${ARTIFACT_LIST_FILE}" ]; then 196 | copy_artifacts "${ARTIFACT_LIST_FILE}" 197 | fi 198 | 199 | if [[ "$CONFIGURATION" == "Debug" ]]; then 200 | install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework" 201 | fi 202 | if [[ "$CONFIGURATION" == "Release" ]]; then 203 | install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework" 204 | fi 205 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 206 | wait 207 | fi 208 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_segmentation_apiVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_segmentation_apiVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CFNetwork" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_segmentation_api { 2 | umbrella header "Pods-segmentation_api-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-segmentation_api/Pods-segmentation_api.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CFNetwork" 7 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from pixellib.semantic import semantic_segmentation 2 | from pixellib.instance import instance_segmentation 3 | from flask import Flask, request 4 | from flask_restful import Resource, Api 5 | from PIL import Image 6 | import base64 7 | from io import BytesIO 8 | 9 | 10 | SEMANTIC_MODEL = "./models/deeplabv3_xception_tf_dim_ordering_tf_kernels.h5" 11 | INSTANCE_MODEL = "./models/mask_rcnn_coco.h5" 12 | 13 | INPUT_IMAGE = "./images/input.jpg" 14 | OUTPUT_IMAGE = "./output_images/output.jpg" 15 | 16 | 17 | app = Flask(__name__) 18 | api = Api(app) 19 | 20 | 21 | class SemanticSegmentation(Resource): 22 | 23 | def post(self): 24 | if request.json: 25 | image = request.json['image'] 26 | image_string = base64.b64decode(image) 27 | image_data = BytesIO(image_string) 28 | img = Image.open(image_data) 29 | img.save(INPUT_IMAGE) 30 | semantic_segment_image = semantic_segmentation() 31 | semantic_segment_image.load_pascalvoc_model(SEMANTIC_MODEL) 32 | semantic_segment_image.segmentAsPascalvoc(INPUT_IMAGE, output_image_name=OUTPUT_IMAGE) 33 | 34 | with open(OUTPUT_IMAGE, "rb") as img_file: 35 | my_string = base64.b64encode(img_file.read()) 36 | final_base64_image_string = my_string.decode('utf-8') 37 | return {"output_image": final_base64_image_string} 38 | 39 | 40 | class InstanceSegmentation(Resource): 41 | 42 | def post(self): 43 | if request.json: 44 | image = request.json['image'] 45 | image_string = base64.b64decode(image) 46 | image_data = BytesIO(image_string) 47 | img = Image.open(image_data) 48 | img.save(INPUT_IMAGE) 49 | instance_segment_image = instance_segmentation() 50 | instance_segment_image.load_model(INSTANCE_MODEL) 51 | instance_segment_image.segmentImage(INPUT_IMAGE, output_image_name=OUTPUT_IMAGE, show_bboxes=True) 52 | 53 | with open(OUTPUT_IMAGE, "rb") as img_file: 54 | my_string = base64.b64encode(img_file.read()) 55 | final_base64_image_string = my_string.decode('utf-8') 56 | return {"output_image": final_base64_image_string} 57 | 58 | 59 | api.add_resource(SemanticSegmentation, '/semantic') 60 | api.add_resource(InstanceSegmentation, '/instance') 61 | 62 | if __name__ == '__main__': 63 | app.run(debug=True) 64 | -------------------------------------------------------------------------------- /instance_segmentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/instance_segmentation.png -------------------------------------------------------------------------------- /instance_segmentation_compression_ratio_comparaison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/instance_segmentation_compression_ratio_comparaison.png -------------------------------------------------------------------------------- /segmentation_api.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /segmentation_api.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /segmentation_api.xcodeproj/xcuserdata/omarmhaimdat.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | segmentation_api.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 2 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /segmentation_api.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /segmentation_api.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /segmentation_api/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // segmentation_api 4 | // 5 | // Created by M'haimdat omar on 21-05-2020. 6 | // Copyright © 2020 M'haimdat omar. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | 21 | // MARK: UISceneSession Lifecycle 22 | 23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 24 | // Called when a new scene session is being created. 25 | // Use this method to select a configuration to create the new scene with. 26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 27 | } 28 | 29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 30 | // Called when the user discards a scene session. 31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 33 | } 34 | 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Icon-40.png", 5 | "idiom" : "iphone", 6 | "scale" : "2x", 7 | "size" : "20x20" 8 | }, 9 | { 10 | "filename" : "Icon-60.png", 11 | "idiom" : "iphone", 12 | "scale" : "3x", 13 | "size" : "20x20" 14 | }, 15 | { 16 | "filename" : "Icon-58.png", 17 | "idiom" : "iphone", 18 | "scale" : "2x", 19 | "size" : "29x29" 20 | }, 21 | { 22 | "filename" : "Icon-87.png", 23 | "idiom" : "iphone", 24 | "scale" : "3x", 25 | "size" : "29x29" 26 | }, 27 | { 28 | "filename" : "Icon-80.png", 29 | "idiom" : "iphone", 30 | "scale" : "2x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "filename" : "Icon-120.png", 35 | "idiom" : "iphone", 36 | "scale" : "3x", 37 | "size" : "40x40" 38 | }, 39 | { 40 | "filename" : "Icon-121.png", 41 | "idiom" : "iphone", 42 | "scale" : "2x", 43 | "size" : "60x60" 44 | }, 45 | { 46 | "filename" : "Icon-180.png", 47 | "idiom" : "iphone", 48 | "scale" : "3x", 49 | "size" : "60x60" 50 | }, 51 | { 52 | "filename" : "Icon-20.png", 53 | "idiom" : "ipad", 54 | "scale" : "1x", 55 | "size" : "20x20" 56 | }, 57 | { 58 | "filename" : "Icon-41.png", 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "20x20" 62 | }, 63 | { 64 | "filename" : "Icon-29.png", 65 | "idiom" : "ipad", 66 | "scale" : "1x", 67 | "size" : "29x29" 68 | }, 69 | { 70 | "filename" : "Icon-59.png", 71 | "idiom" : "ipad", 72 | "scale" : "2x", 73 | "size" : "29x29" 74 | }, 75 | { 76 | "filename" : "Icon-42.png", 77 | "idiom" : "ipad", 78 | "scale" : "1x", 79 | "size" : "40x40" 80 | }, 81 | { 82 | "filename" : "Icon-81.png", 83 | "idiom" : "ipad", 84 | "scale" : "2x", 85 | "size" : "40x40" 86 | }, 87 | { 88 | "filename" : "Icon-76.png", 89 | "idiom" : "ipad", 90 | "scale" : "1x", 91 | "size" : "76x76" 92 | }, 93 | { 94 | "filename" : "Icon-152.png", 95 | "idiom" : "ipad", 96 | "scale" : "2x", 97 | "size" : "76x76" 98 | }, 99 | { 100 | "filename" : "Icon-167.png", 101 | "idiom" : "ipad", 102 | "scale" : "2x", 103 | "size" : "83.5x83.5" 104 | }, 105 | { 106 | "filename" : "Icon-1024.png", 107 | "idiom" : "ios-marketing", 108 | "scale" : "1x", 109 | "size" : "1024x1024" 110 | } 111 | ], 112 | "info" : { 113 | "author" : "xcode", 114 | "version" : 1 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-1024.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-120.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-121.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-121.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-152.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-167.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-180.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-20.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-29.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-41.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-41.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-42.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-42.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-58.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-59.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-59.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-60.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-80.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-81.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-81.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/AppIcon.appiconset/Icon-87.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/cover.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "cover.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/cover.imageset/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/cover.imageset/cover.png -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/profile.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "profile.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /segmentation_api/Assets.xcassets/profile.imageset/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/segmentation_api/Assets.xcassets/profile.imageset/profile.png -------------------------------------------------------------------------------- /segmentation_api/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /segmentation_api/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSCameraUsageDescription 6 | We need access to the camera to perform segmentation 7 | NSAppleMusicUsageDescription 8 | We need access to the image library in order to upload images 9 | CFBundleDevelopmentRegion 10 | $(DEVELOPMENT_LANGUAGE) 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | UIApplicationSceneManifest 28 | 29 | UIApplicationSupportsMultipleScenes 30 | 31 | UISceneConfigurations 32 | 33 | UIWindowSceneSessionRoleApplication 34 | 35 | 36 | UISceneConfigurationName 37 | Default Configuration 38 | UISceneDelegateClassName 39 | $(PRODUCT_MODULE_NAME).SceneDelegate 40 | 41 | 42 | 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIRequiredDeviceCapabilities 47 | 48 | armv7 49 | 50 | UISupportedInterfaceOrientations 51 | 52 | UIInterfaceOrientationPortrait 53 | 54 | UISupportedInterfaceOrientations~ipad 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationPortraitUpsideDown 58 | UIInterfaceOrientationLandscapeLeft 59 | UIInterfaceOrientationLandscapeRight 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /segmentation_api/MyButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyButton.swift 3 | // segmentation_api 4 | // 5 | // Created by M'haimdat omar on 21-05-2020. 6 | // Copyright © 2020 M'haimdat omar. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MyButton: UIButton { 12 | 13 | override func awakeFromNib() { 14 | super.awakeFromNib() 15 | 16 | } 17 | 18 | override init(frame: CGRect) { 19 | 20 | super.init(frame: frame) 21 | 22 | backgroundColor = .white 23 | layer.borderWidth = 2 24 | layer.backgroundColor = UIColor.white.cgColor 25 | setTitleColor(#colorLiteral(red: 0.5, green: 0.06049922854, blue: 0.07871029526, alpha: 1), for: .normal) 26 | titleLabel?.font = UIFont(name: "Avenir-Heavy", size: 25) 27 | layer.borderColor = #colorLiteral(red: 0.5, green: 0.06049922854, blue: 0.07871029526, alpha: 1).cgColor 28 | layer.cornerRadius = 30 29 | setTitle("Upload an image", for: .normal) 30 | let icon = UIImage(systemName: "square.and.arrow.up")?.resized(newSize: CGSize(width: 35, height: 35)) 31 | 32 | let newIcon = icon?.withTintColor(#colorLiteral(red: 0.5, green: 0.06049922854, blue: 0.07871029526, alpha: 1)) 33 | self.setImage( newIcon, for: .normal) 34 | self.imageEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 100) 35 | self.layoutIfNeeded() 36 | contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16) 37 | contentHorizontalAlignment = .center 38 | layer.shadowOpacity = 0.4 39 | layer.shadowColor = #colorLiteral(red: 0.5, green: 0.06049922854, blue: 0.07871029526, alpha: 1).cgColor 40 | layer.shadowRadius = 10 41 | layer.masksToBounds = true 42 | clipsToBounds = false 43 | titleEdgeInsets.left = 15 44 | } 45 | 46 | required init?(coder aDecoder: NSCoder) { 47 | fatalError("init(coder:) has not been implemented") 48 | } 49 | } 50 | 51 | extension UIImage { 52 | 53 | func resized(newSize:CGSize) -> UIImage { 54 | UIGraphicsBeginImageContextWithOptions(newSize, false, UIScreen.main.scale) 55 | self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)) 56 | let newImage = UIGraphicsGetImageFromCurrentImageContext() 57 | UIGraphicsEndImageContext() 58 | 59 | return newImage! 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /segmentation_api/OutputViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OutputViewController.swift 3 | // segmentation_api 4 | // 5 | // Created by M'haimdat omar on 21-05-2020. 6 | // Copyright © 2020 M'haimdat omar. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Alamofire 11 | 12 | class OutputViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { 13 | 14 | var apiEntryPoint = "" 15 | 16 | var barTitle = "" 17 | 18 | lazy var outputImage: UIImageView = { 19 | let image = UIImageView() 20 | image.translatesAutoresizingMaskIntoConstraints = false 21 | image.contentMode = .scaleAspectFit 22 | image.layer.masksToBounds = true 23 | return image 24 | }() 25 | 26 | lazy var uploadBtn : MyButton = { 27 | let btn = MyButton() 28 | btn.translatesAutoresizingMaskIntoConstraints = false 29 | btn.addTarget(self, action: #selector(buttonToUpload(_:)), for: .touchUpInside) 30 | return btn 31 | }() 32 | 33 | lazy var cameraBtn : MyButton = { 34 | let btn = MyButton() 35 | btn.translatesAutoresizingMaskIntoConstraints = false 36 | btn.addTarget(self, action: #selector(buttonToCamera(_:)), for: .touchUpInside) 37 | btn.setTitle("Take an image ", for: .normal) 38 | let icon = UIImage(systemName: "camera")?.resized(newSize: CGSize(width: 45, height: 35)) 39 | let finalIcon = icon?.withTintColor(#colorLiteral(red: 0.5, green: 0.06049922854, blue: 0.07871029526, alpha: 1)) 40 | btn.setImage(finalIcon, for: .normal) 41 | btn.imageEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 100) 42 | btn.layoutIfNeeded() 43 | return btn 44 | }() 45 | 46 | lazy var dissmissButton : MyButton = { 47 | let btn = MyButton() 48 | btn.translatesAutoresizingMaskIntoConstraints = false 49 | btn.addTarget(self, action: #selector(buttonToDissmiss(_:)), for: .touchUpInside) 50 | btn.setTitle("Dismiss", for: .normal) 51 | let icon = UIImage(systemName: "xmark.circle")?.resized(newSize: CGSize(width: 35, height: 35)) 52 | let finalIcon = icon?.withTintColor(.systemBackground) 53 | btn.setImage(finalIcon, for: .normal) 54 | btn.setTitleColor(.systemBackground, for: .normal) 55 | btn.backgroundColor = #colorLiteral(red: 0.5, green: 0.06049922854, blue: 0.07871029526, alpha: 1) 56 | btn.imageEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 100) 57 | btn.layer.borderColor = UIColor.systemBackground.cgColor 58 | btn.layoutIfNeeded() 59 | return btn 60 | }() 61 | 62 | override func viewDidLoad() { 63 | super.viewDidLoad() 64 | view.backgroundColor = .systemBackground 65 | addSubviews() 66 | setupLayout() 67 | setupTabBar() 68 | } 69 | 70 | func setupTabBar() { 71 | navigationController?.navigationBar.prefersLargeTitles = true 72 | self.navigationItem.title = self.barTitle 73 | if #available(iOS 13.0, *) { 74 | self.navigationController?.navigationBar.barTintColor = .systemBackground 75 | navigationController?.navigationBar.titleTextAttributes = [.foregroundColor : UIColor.label] 76 | } else { 77 | self.navigationController?.navigationBar.barTintColor = .lightText 78 | navigationController?.navigationBar.titleTextAttributes = [.foregroundColor : UIColor.black] 79 | } 80 | self.navigationController?.navigationBar.isHidden = false 81 | self.setNeedsStatusBarAppearanceUpdate() 82 | self.navigationItem.largeTitleDisplayMode = .automatic 83 | self.navigationController?.navigationBar.barStyle = .default 84 | if #available(iOS 13.0, *) { 85 | navigationController?.navigationBar.largeTitleTextAttributes = [.foregroundColor : UIColor.label] 86 | } else { 87 | navigationController?.navigationBar.largeTitleTextAttributes = [.foregroundColor : UIColor.black] 88 | } 89 | if #available(iOS 13.0, *) { 90 | navigationController?.navigationBar.backgroundColor = .systemBackground 91 | } else { 92 | navigationController?.navigationBar.backgroundColor = .white 93 | } 94 | self.tabBarController?.tabBar.isHidden = false 95 | } 96 | 97 | func addSubviews() { 98 | 99 | view.addSubview(outputImage) 100 | view.addSubview(uploadBtn) 101 | view.addSubview(cameraBtn) 102 | view.addSubview(dissmissButton) 103 | } 104 | 105 | func setupLayout() { 106 | 107 | outputImage.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 108 | outputImage.widthAnchor.constraint(equalToConstant: view.frame.width).isActive = true 109 | outputImage.bottomAnchor.constraint(equalTo: uploadBtn.topAnchor, constant: -50).isActive = true 110 | 111 | uploadBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 112 | uploadBtn.widthAnchor.constraint(equalToConstant: view.frame.width - 40).isActive = true 113 | uploadBtn.heightAnchor.constraint(equalToConstant: 65).isActive = true 114 | uploadBtn.bottomAnchor.constraint(equalTo: cameraBtn.topAnchor, constant: -30).isActive = true 115 | 116 | cameraBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 117 | cameraBtn.widthAnchor.constraint(equalToConstant: view.frame.width - 40).isActive = true 118 | cameraBtn.heightAnchor.constraint(equalToConstant: 65).isActive = true 119 | cameraBtn.bottomAnchor.constraint(equalTo: dissmissButton.topAnchor, constant: -30).isActive = true 120 | 121 | dissmissButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 122 | dissmissButton.heightAnchor.constraint(equalToConstant: 65).isActive = true 123 | dissmissButton.widthAnchor.constraint(equalToConstant: view.frame.width - 40).isActive = true 124 | dissmissButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -50).isActive = true 125 | 126 | } 127 | 128 | func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { 129 | // your chosen image 130 | let pickedImage = info[UIImagePickerController.InfoKey.editedImage] as! UIImage 131 | 132 | self.outputImage.image = pickedImage.resized(newSize: CGSize(width: 350, height: 350)) 133 | 134 | self.outputImage.showSpinner() 135 | 136 | // convert the UIImage to base64 encoding 137 | let imageDataBase64 = pickedImage.jpegData(compressionQuality: 0.2)!.base64EncodedString(options: .lineLength64Characters) 138 | print(imageDataBase64) 139 | 140 | let parameters: Parameters = ["image": imageDataBase64] 141 | 142 | AF.request(URL.init(string: self.apiEntryPoint)!, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: .none).responseJSON { (response) in 143 | print(response.result) 144 | 145 | switch response.result { 146 | 147 | case .success(let value): 148 | if let JSON = value as? [String: Any] { 149 | let base64StringOutput = JSON["output_image"] as! String 150 | let newImageData = Data(base64Encoded: base64StringOutput) 151 | if let newImageData = newImageData { 152 | let outputImage = UIImage(data: newImageData) 153 | let finalOutputImage = outputImage!.resized(newSize: CGSize(width: 350, height: 350)) 154 | self.outputImage.removeSpinner() 155 | self.outputImage.image = finalOutputImage 156 | } 157 | } 158 | break 159 | case .failure(let error): 160 | print(error) 161 | break 162 | } 163 | 164 | } 165 | 166 | picker.dismiss(animated: true, completion: nil) 167 | } 168 | 169 | 170 | @objc func buttonToUpload(_ sender: MyButton) { 171 | if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) { 172 | let imagePicker = UIImagePickerController() 173 | imagePicker.delegate = self 174 | imagePicker.sourceType = .photoLibrary 175 | imagePicker.allowsEditing = true 176 | self.present(imagePicker, animated: true, completion: nil) 177 | } 178 | } 179 | 180 | @objc func buttonToCamera(_ sender: MyButton) { 181 | if UIImagePickerController.isSourceTypeAvailable(.camera) { 182 | let imagePicker = UIImagePickerController() 183 | imagePicker.delegate = self 184 | imagePicker.sourceType = .camera 185 | imagePicker.allowsEditing = true 186 | self.present(imagePicker, animated: true, completion: nil) 187 | } 188 | } 189 | 190 | @objc func buttonToDissmiss(_ sender: UIButton) { 191 | self.dismiss(animated: true, completion: nil) 192 | } 193 | 194 | 195 | } 196 | 197 | var view: UIView? 198 | 199 | extension UIImageView { 200 | 201 | func showSpinner() { 202 | view = UIView(frame: CGRect(x: 0, y: 0, width: 350, height: 350)) 203 | print(self.bounds) 204 | view!.backgroundColor = .clear 205 | 206 | let spinner = UIActivityIndicatorView(style: .large) 207 | spinner.color = #colorLiteral(red: 0.5, green: 0.06049922854, blue: 0.07871029526, alpha: 1) 208 | spinner.center = view!.center 209 | spinner.startAnimating() 210 | view!.addSubview(spinner) 211 | self.addSubview(view!) 212 | } 213 | 214 | func removeSpinner() { 215 | view!.removeFromSuperview() 216 | view = nil 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /segmentation_api/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // segmentation_api 4 | // 5 | // Created by M'haimdat omar on 21-05-2020. 6 | // Copyright © 2020 M'haimdat omar. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 12 | 13 | var window: UIWindow? 14 | 15 | 16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 17 | guard let windowScene = (scene as? UIWindowScene) else { return } 18 | 19 | window = UIWindow(frame: windowScene.coordinateSpace.bounds) 20 | window?.windowScene = windowScene 21 | window?.rootViewController = ViewController() 22 | window?.makeKeyAndVisible() 23 | } 24 | 25 | func sceneDidDisconnect(_ scene: UIScene) { 26 | // Called as the scene is being released by the system. 27 | // This occurs shortly after the scene enters the background, or when its session is discarded. 28 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 29 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 30 | } 31 | 32 | func sceneDidBecomeActive(_ scene: UIScene) { 33 | // Called when the scene has moved from an inactive state to an active state. 34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 35 | } 36 | 37 | func sceneWillResignActive(_ scene: UIScene) { 38 | // Called when the scene will move from an active state to an inactive state. 39 | // This may occur due to temporary interruptions (ex. an incoming phone call). 40 | } 41 | 42 | func sceneWillEnterForeground(_ scene: UIScene) { 43 | // Called as the scene transitions from the background to the foreground. 44 | // Use this method to undo the changes made on entering the background. 45 | } 46 | 47 | func sceneDidEnterBackground(_ scene: UIScene) { 48 | // Called as the scene transitions from the foreground to the background. 49 | // Use this method to save data, release shared resources, and store enough scene-specific state information 50 | // to restore the scene back to its current state. 51 | } 52 | 53 | 54 | } 55 | 56 | -------------------------------------------------------------------------------- /segmentation_api/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // segmentation_api 4 | // 5 | // Created by M'haimdat omar on 21-05-2020. 6 | // Copyright © 2020 M'haimdat omar. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Alamofire 11 | 12 | let screenWidth = UIScreen.main.bounds.width 13 | 14 | class ViewController: UIViewController { 15 | 16 | lazy var name: UILabel = { 17 | let text = UILabel() 18 | text.translatesAutoresizingMaskIntoConstraints = false 19 | text.font = UIFont(name: "Avenir-Heavy", size: 35) 20 | text.text = "Segmentation API" 21 | text.textColor = #colorLiteral(red: 0.4980392157, green: 0.05882352941, blue: 0.07843137255, alpha: 1) 22 | return text 23 | 24 | }() 25 | 26 | lazy var logo: UIImageView = { 27 | let image = UIImageView(image: #imageLiteral(resourceName: "profile")) 28 | image.translatesAutoresizingMaskIntoConstraints = false 29 | return image 30 | }() 31 | 32 | lazy var semanticBtn : MyButton = { 33 | let btn = MyButton() 34 | btn.translatesAutoresizingMaskIntoConstraints = false 35 | btn.addTarget(self, action: #selector(buttonToSemanticSegmentation(_:)), for: .touchUpInside) 36 | btn.setTitle("Semantic segmentation", for: .normal) 37 | let icon = UIImage(systemName: "map")?.resized(newSize: CGSize(width: 35, height: 35)) 38 | let finalIcon = icon?.withTintColor(#colorLiteral(red: 0.5, green: 0.06049922854, blue: 0.07871029526, alpha: 1)) 39 | btn.setImage(finalIcon, for: .normal) 40 | btn.imageEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 100) 41 | btn.layoutIfNeeded() 42 | return btn 43 | }() 44 | 45 | lazy var instanceBtn : MyButton = { 46 | let btn = MyButton() 47 | btn.translatesAutoresizingMaskIntoConstraints = false 48 | btn.addTarget(self, action: #selector(buttonToInstanceSegmentation(_:)), for: .touchUpInside) 49 | btn.setTitle("Instance segmentation", for: .normal) 50 | let icon = UIImage(systemName: "map.fill")?.resized(newSize: CGSize(width: 45, height: 35)) 51 | let finalIcon = icon?.withTintColor(#colorLiteral(red: 0.5, green: 0.06049922854, blue: 0.07871029526, alpha: 1)) 52 | btn.setImage(finalIcon, for: .normal) 53 | btn.imageEdgeInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 100) 54 | btn.layoutIfNeeded() 55 | return btn 56 | }() 57 | 58 | override func viewDidLoad() { 59 | super.viewDidLoad() 60 | view.backgroundColor = .systemBackground 61 | addElementsToSubview() 62 | setupView() 63 | } 64 | 65 | fileprivate func addElementsToSubview() { 66 | view.addSubview(name) 67 | view.addSubview(logo) 68 | view.addSubview(semanticBtn) 69 | view.addSubview(instanceBtn) 70 | } 71 | 72 | fileprivate func setupView() { 73 | 74 | logo.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true 75 | logo.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 50).isActive = true 76 | logo.widthAnchor.constraint(equalToConstant: 200).isActive = true 77 | logo.heightAnchor.constraint(equalToConstant: 200).isActive = true 78 | 79 | instanceBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 80 | instanceBtn.widthAnchor.constraint(equalToConstant: view.frame.width - 40).isActive = true 81 | instanceBtn.heightAnchor.constraint(equalToConstant: 65).isActive = true 82 | instanceBtn.bottomAnchor.constraint(equalTo: semanticBtn.topAnchor, constant: -40).isActive = true 83 | 84 | semanticBtn.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 85 | semanticBtn.widthAnchor.constraint(equalToConstant: view.frame.width - 40).isActive = true 86 | semanticBtn.heightAnchor.constraint(equalToConstant: 65).isActive = true 87 | semanticBtn.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -120).isActive = true 88 | 89 | name.topAnchor.constraint(equalTo: view.topAnchor, constant: 250).isActive = true 90 | name.heightAnchor.constraint(equalToConstant: 100).isActive = true 91 | name.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true 92 | name.numberOfLines = 1 93 | 94 | } 95 | 96 | @objc func buttonToSemanticSegmentation(_ sender: MyButton) { 97 | let controller = OutputViewController() 98 | controller.apiEntryPoint = "http://127.0.0.1:5000/semantic" 99 | controller.barTitle = "Semantic" 100 | 101 | let navController = UINavigationController(rootViewController: controller) 102 | 103 | self.present(navController, animated: true, completion: nil) 104 | } 105 | 106 | @objc func buttonToInstanceSegmentation(_ sender: MyButton) { 107 | let controller = OutputViewController() 108 | controller.apiEntryPoint = "http://127.0.0.1:5000/instance" 109 | controller.barTitle = "Instance" 110 | 111 | let navController = UINavigationController(rootViewController: controller) 112 | 113 | self.present(navController, animated: true, completion: nil) 114 | } 115 | 116 | 117 | } 118 | 119 | -------------------------------------------------------------------------------- /semantic_segmentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omarmhaimdat/segmentation_api/702a4bb0700118bbc0f052d20c3f846524abcf76/semantic_segmentation.png --------------------------------------------------------------------------------