diff --git a/BSRadioWaves.xcodeproj/project.pbxproj b/BSRadioWaves.xcodeproj/project.pbxproj
index 1479b83..66c579a 100644
--- a/BSRadioWaves.xcodeproj/project.pbxproj
+++ b/BSRadioWaves.xcodeproj/project.pbxproj
@@ -50,7 +50,6 @@
062E7F0F1FB1A73500217A3B /* BSPlayButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062E7F0E1FB1A73500217A3B /* BSPlayButton.swift */; };
062E7F111FB1A96900217A3B /* BSPlayPauseIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062E7F101FB1A96900217A3B /* BSPlayPauseIconView.swift */; };
062E7F131FB1BF4A00217A3B /* BSTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062E7F121FB1BF4A00217A3B /* BSTabBarController.swift */; };
- 063A3B091FBB0DBD00E64373 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 063A3B081FBB0DBD00E64373 /* Assets.xcassets */; };
063A3B0A1FBB0DCF00E64373 /* Assets.xcassets in Sources */ = {isa = PBXBuildFile; fileRef = 063A3B081FBB0DBD00E64373 /* Assets.xcassets */; };
0640D24D1FC2E8D300E9ECB2 /* BSCategoriesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06B22B2E1FC2CA070085FF30 /* BSCategoriesController.swift */; };
06593EEC1FAA51BA00689EA7 /* BSCategoriesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06593EE41FAA51BA00689EA7 /* BSCategoriesViewController.swift */; };
@@ -97,7 +96,6 @@
06B22B171FC1A24B0085FF30 /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06B22B161FC1A24B0085FF30 /* ExtensionDelegate.swift */; };
06B22B191FC1A24B0085FF30 /* NotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06B22B181FC1A24B0085FF30 /* NotificationController.swift */; };
06B22B1B1FC1A24B0085FF30 /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06B22B1A1FC1A24B0085FF30 /* ComplicationController.swift */; };
- 06B22B1D1FC1A24B0085FF30 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 06B22B1C1FC1A24B0085FF30 /* Assets.xcassets */; };
06B22B221FC1A24B0085FF30 /* Watch.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 06B22B031FC1A24A0085FF30 /* Watch.app */; };
06CC90A41FC56A8B0033EF22 /* BSWavesDrawerProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CC90A31FC56A8B0033EF22 /* BSWavesDrawerProxy.swift */; };
06CC90A71FC56E9F0033EF22 /* BSWavesDrawer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CC90A61FC56E9E0033EF22 /* BSWavesDrawer.swift */; };
@@ -672,7 +670,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0910;
- LastUpgradeCheck = 0900;
+ LastUpgradeCheck = 1100;
ORGANIZATIONNAME = iBlacksus;
TargetAttributes = {
06593EC51FA91A5D00689EA7 = {
@@ -721,7 +719,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 063A3B091FBB0DBD00E64373 /* Assets.xcassets in Resources */,
06EF3E371FBC27BD00CB18E4 /* BSLikeCell.xib in Resources */,
061C0AD31FBAD1CF003E6066 /* Roboto-ThinItalic.ttf in Resources */,
061C0AD41FBAD1CF003E6066 /* Roboto-BoldItalic.ttf in Resources */,
@@ -768,7 +765,6 @@
buildActionMask = 2147483647;
files = (
061F72F71FC6A5E2003919D5 /* Assets.xcassets in Resources */,
- 06B22B1D1FC1A24B0085FF30 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -817,7 +813,7 @@
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh",
+ "${PODS_ROOT}/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Alamofire-iOS/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/AlamofireObjectMapper-iOS/AlamofireObjectMapper.framework",
"${BUILT_PRODUCTS_DIR}/CryptoSwift-iOS/CryptoSwift.framework",
@@ -836,7 +832,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh\"\n";
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
B018866A18BC29AF68E7962F /* [CP] Embed Pods Frameworks */ = {
@@ -845,7 +841,7 @@
files = (
);
inputPaths = (
- "${SRCROOT}/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh",
+ "${PODS_ROOT}/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Alamofire-watchOS/Alamofire.framework",
"${BUILT_PRODUCTS_DIR}/AlamofireObjectMapper-watchOS/AlamofireObjectMapper.framework",
"${BUILT_PRODUCTS_DIR}/CryptoSwift-watchOS/CryptoSwift.framework",
@@ -862,7 +858,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh\"\n";
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -1010,6 +1006,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
@@ -1017,6 +1014,7 @@
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -1067,6 +1065,7 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
@@ -1074,6 +1073,7 @@
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
@@ -1114,6 +1114,7 @@
INFOPLIST_FILE = BSRadioWaves/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "5f9082d6-2a97-4799-96ee-dceaf03439a6";
@@ -1135,6 +1136,7 @@
INFOPLIST_FILE = BSRadioWaves/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1152,6 +1154,7 @@
DEVELOPMENT_TEAM = LS7LKYHTNJ;
INFOPLIST_FILE = "Watch Extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves.watchkitapp.watchkitextension;
PRODUCT_NAME = "${TARGET_NAME}";
PROVISIONING_PROFILE = "f6d5cd5e-aa4c-4380-a6c2-14f9fad81fd8";
@@ -1173,6 +1176,7 @@
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "Watch Extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
+ ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves.watchkitapp.watchkitextension;
PRODUCT_NAME = "${TARGET_NAME}";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1195,6 +1199,7 @@
IBSC_MODULE = Watch_Extension;
INFOPLIST_FILE = Watch/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "f6d5cd5e-aa4c-4380-a6c2-14f9fad81fd8";
@@ -1219,6 +1224,7 @@
IBSC_MODULE = Watch_Extension;
INFOPLIST_FILE = Watch/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+ ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves.watchkitapp;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
diff --git a/BSRadioWaves.xcworkspace/contents.xcworkspacedata b/BSRadioWaves.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..58a7f26
--- /dev/null
+++ b/BSRadioWaves.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/BSRadioWaves.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/BSRadioWaves.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/BSRadioWaves.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/BSRadioWaves/Classes/BSAppDelegate.swift b/BSRadioWaves/Classes/BSAppDelegate.swift
index 55d314a..f29a1e0 100644
--- a/BSRadioWaves/Classes/BSAppDelegate.swift
+++ b/BSRadioWaves/Classes/BSAppDelegate.swift
@@ -22,7 +22,7 @@ class BSAppDelegate: UIResponder, UIApplicationDelegate {
var style = ToastStyle()
style.backgroundColor = UIColor.black.withAlphaComponent(0.4)
ToastManager.shared.style = style
- ToastManager.shared.tapToDismissEnabled = true
+ ToastManager.shared.isTapToDismissEnabled = true
SDImageCache.shared().config.maxCacheAge = 60 * 60 * 24
diff --git a/BSRadioWaves/Classes/Likes/BSLikesView.swift b/BSRadioWaves/Classes/Likes/BSLikesView.swift
index da69bb5..b4395ae 100644
--- a/BSRadioWaves/Classes/Likes/BSLikesView.swift
+++ b/BSRadioWaves/Classes/Likes/BSLikesView.swift
@@ -40,9 +40,11 @@ class BSLikesView: UICollectionView, UICollectionViewDelegate, UICollectionViewD
let cellRect: CGRect = (attributes?.frame)!
let view: UIView = collectionView.superview!
let cellFrameInSuperview = collectionView.convert(cellRect, to: view)
- let position = CGPoint(x: cellFrameInSuperview.midX, y: cellFrameInSuperview.midY)
+// let position = CGPoint(x: cellFrameInSuperview.midX, y: cellFrameInSuperview.midY)
- self.makeToast("Copied to clipboard", duration: 1.25, position: position)
+ self.makeToast("Copied to clipboard", duration: 1.25, position: .bottom, title: "", image: nil) { (success) in
+
+ }
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
diff --git a/Pods/Alamofire/LICENSE b/Pods/Alamofire/LICENSE
new file mode 100644
index 0000000..38a301a
--- /dev/null
+++ b/Pods/Alamofire/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Pods/Alamofire/README.md b/Pods/Alamofire/README.md
new file mode 100644
index 0000000..9fdc9c7
--- /dev/null
+++ b/Pods/Alamofire/README.md
@@ -0,0 +1,242 @@
+
+
+[](https://travis-ci.org/Alamofire/Alamofire)
+[](https://img.shields.io/cocoapods/v/Alamofire.svg)
+[](https://github.com/Carthage/Carthage)
+[](https://alamofire.github.io/Alamofire)
+[](https://twitter.com/AlamofireSF)
+[](https://gitter.im/Alamofire/Alamofire?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+Alamofire is an HTTP networking library written in Swift.
+
+- [Features](#features)
+- [Component Libraries](#component-libraries)
+- [Requirements](#requirements)
+- [Migration Guides](#migration-guides)
+- [Communication](#communication)
+- [Installation](#installation)
+- [Usage](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md)
+ - **Intro -** [Making a Request](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#making-a-request), [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)
+ - **HTTP -** [HTTP Methods](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#http-methods), [Parameter Encoding](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#parameter-encoding), [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)
+ - **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)
+ - **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)
+- [Advanced Usage](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md)
+ - **URL Session -** [Session Manager](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#session-manager), [Session Delegate](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#session-delegate), [Request](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#request)
+ - **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)
+ - **Model Objects -** [Custom Response Serialization](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#custom-response-serialization)
+ - **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)
+- [Open Radars](#open-radars)
+- [FAQ](#faq)
+- [Credits](#credits)
+- [Donations](#donations)
+- [License](#license)
+
+## Features
+
+- [x] Chainable Request / Response Methods
+- [x] URL / JSON / plist Parameter Encoding
+- [x] Upload File / Data / Stream / MultipartFormData
+- [x] Download File using Request or Resume Data
+- [x] Authentication with URLCredential
+- [x] HTTP Response Validation
+- [x] Upload and Download Progress Closures with Progress
+- [x] cURL Command Output
+- [x] Dynamically Adapt and Retry Requests
+- [x] TLS Certificate and Public Key Pinning
+- [x] Network Reachability
+- [x] Comprehensive Unit and Integration Test Coverage
+- [x] [Complete Documentation](https://alamofire.github.io/Alamofire)
+
+## Component Libraries
+
+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.
+
+- [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.
+- [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.
+
+## Requirements
+
+- iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+
+- Xcode 8.3+
+- Swift 3.1+
+
+## Migration Guides
+
+- [Alamofire 4.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%204.0%20Migration%20Guide.md)
+- [Alamofire 3.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%203.0%20Migration%20Guide.md)
+- [Alamofire 2.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%202.0%20Migration%20Guide.md)
+
+## Communication
+- If you **need help with making network requests**, use [Stack Overflow](https://stackoverflow.com/questions/tagged/alamofire) and tag `alamofire`.
+- 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.
+- If you need **help with an Alamofire feature**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire).
+- If you'd like to **discuss Alamofire best practices**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire).
+- If you'd like to **discuss a feature request**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire).
+- If you **found a bug**, open an issue and follow the guide. The more detail the better!
+- If you **want to contribute**, submit a pull request.
+
+## Installation
+
+### CocoaPods
+
+[CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:
+
+```bash
+$ gem install cocoapods
+```
+
+> CocoaPods 1.7+ is required to build Alamofire 4.9+.
+
+To integrate Alamofire into your Xcode project using CocoaPods, specify it in your `Podfile`:
+
+```ruby
+source 'https://github.com/CocoaPods/Specs.git'
+platform :ios, '10.0'
+use_frameworks!
+
+target '' do
+ pod 'Alamofire', '~> 4.9'
+end
+```
+
+Then, run the following command:
+
+```bash
+$ pod install
+```
+
+### Carthage
+
+[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
+
+You can install Carthage with [Homebrew](https://brew.sh/) using the following command:
+
+```bash
+$ brew install carthage
+```
+
+To integrate Alamofire into your Xcode project using Carthage, specify it in your `Cartfile`:
+
+```ogdl
+github "Alamofire/Alamofire" ~> 4.9
+```
+
+Run `carthage update` to build the framework and drag the built `Alamofire.framework` into your Xcode project.
+
+### Swift Package Manager
+
+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.
+
+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`.
+
+#### Swift 3
+
+```swift
+dependencies: [
+ .Package(url: "https://github.com/Alamofire/Alamofire.git", majorVersion: 4)
+]
+```
+
+#### Swift 4
+
+```swift
+dependencies: [
+ .package(url: "https://github.com/Alamofire/Alamofire.git", from: "4.9.0")
+]
+```
+
+### Manually
+
+If you prefer not to use any of the aforementioned dependency managers, you can integrate Alamofire into your project manually.
+
+#### Embedded Framework
+
+- 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:
+
+ ```bash
+ $ git init
+ ```
+
+- Add Alamofire as a git [submodule](https://git-scm.com/docs/git-submodule) by running the following command:
+
+ ```bash
+ $ git submodule add https://github.com/Alamofire/Alamofire.git
+ ```
+
+- Open the new `Alamofire` folder, and drag the `Alamofire.xcodeproj` into the Project Navigator of your application's Xcode project.
+
+ > 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.
+
+- Select the `Alamofire.xcodeproj` in the Project Navigator and verify the deployment target matches that of your application target.
+- 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.
+- In the tab bar at the top of that window, open the "General" panel.
+- Click on the `+` button under the "Embedded Binaries" section.
+- You will see two different `Alamofire.xcodeproj` folders each with two different versions of the `Alamofire.framework` nested inside a `Products` folder.
+
+ > It does not matter which `Products` folder you choose from, but it does matter whether you choose the top or bottom `Alamofire.framework`.
+
+- Select the top `Alamofire.framework` for iOS and the bottom one for OS X.
+
+ > 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`.
+
+- And that's it!
+
+ > 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.
+
+## Open Radars
+
+The following radars have some effect on the current implementation of Alamofire.
+
+- [`rdar://21349340`](http://www.openradar.me/radar?id=5517037090635776) - Compiler throwing warning due to toll-free bridging issue in test case
+- `rdar://26870455` - Background URL Session Configurations do not work in the simulator
+- `rdar://26849668` - Some URLProtocol APIs do not properly handle `URLRequest`
+- [`rdar://36082113`](http://openradar.appspot.com/radar?id=4942308441063424) - `URLSessionTaskMetrics` failing to link on watchOS 3.0+
+
+## Resolved Radars
+
+The following radars have been resolved over time after being filed against the Alamofire project.
+
+- [`rdar://26761490`](http://www.openradar.me/radar?id=5010235949318144) - Swift string interpolation causing memory leak with common usage (Resolved on 9/1/17 in Xcode 9 beta 6).
+
+## FAQ
+
+### What's the origin of the name Alamofire?
+
+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.
+
+### What logic belongs in a Router vs. a Request Adapter?
+
+Simple, static data such as paths, parameters and common headers belong in the `Router`. Dynamic data such as an `Authorization` header whose value can changed based on an authentication system belongs in a `RequestAdapter`.
+
+The reason the dynamic data MUST be placed into the `RequestAdapter` is to support retry operations. When a `Request` is retried, the original request is not rebuilt meaning the `Router` will not be called again. The `RequestAdapter` is called again allowing the dynamic data to be updated on the original request before retrying the `Request`.
+
+## Credits
+
+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.
+
+### Security Disclosure
+
+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.
+
+## Donations
+
+The [ASF](https://github.com/Alamofire/Foundation#members) is looking to raise money to officially stay registered as a federal non-profit organization.
+Registering will allow us members to gain some legal protections and also allow us to put donations to use, tax free.
+Donating to the ASF will enable us to:
+
+- Pay our yearly legal fees to keep the non-profit in good status
+- Pay for our mail servers to help us stay on top of all questions and security issues
+- Potentially fund test servers to make it easier for us to test the edge cases
+- Potentially fund developers to work on one of our projects full-time
+
+The community adoption of the ASF libraries has been amazing.
+We are greatly humbled by your enthusiasm around the projects, and want to continue to do everything we can to move the needle forward.
+With your continued support, the ASF will be able to improve its reach and also provide better legal safety for the core members.
+If you use any of our libraries for work, see if your employers would be interested in donating.
+Any amount you can donate today to help us reach our goal would be greatly appreciated.
+
+[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W34WPEE74APJQ)
+
+## License
+
+Alamofire is released under the MIT license. [See LICENSE](https://github.com/Alamofire/Alamofire/blob/master/LICENSE) for details.
diff --git a/Pods/Alamofire/Source/AFError.swift b/Pods/Alamofire/Source/AFError.swift
new file mode 100644
index 0000000..b163f60
--- /dev/null
+++ b/Pods/Alamofire/Source/AFError.swift
@@ -0,0 +1,460 @@
+//
+// AFError.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// `AFError` is the error type returned by Alamofire. It encompasses a few different types of errors, each with
+/// their own associated reasons.
+///
+/// - invalidURL: Returned when a `URLConvertible` type fails to create a valid `URL`.
+/// - parameterEncodingFailed: Returned when a parameter encoding object throws an error during the encoding process.
+/// - multipartEncodingFailed: Returned when some step in the multipart encoding process fails.
+/// - responseValidationFailed: Returned when a `validate()` call fails.
+/// - responseSerializationFailed: Returned when a response serializer encounters an error in the serialization process.
+public enum AFError: Error {
+ /// The underlying reason the parameter encoding error occurred.
+ ///
+ /// - missingURL: The URL request did not have a URL to encode.
+ /// - jsonEncodingFailed: JSON serialization failed with an underlying system error during the
+ /// encoding process.
+ /// - propertyListEncodingFailed: Property list serialization failed with an underlying system error during
+ /// encoding process.
+ public enum ParameterEncodingFailureReason {
+ case missingURL
+ case jsonEncodingFailed(error: Error)
+ case propertyListEncodingFailed(error: Error)
+ }
+
+ /// The underlying reason the multipart encoding error occurred.
+ ///
+ /// - bodyPartURLInvalid: The `fileURL` provided for reading an encodable body part isn't a
+ /// file URL.
+ /// - bodyPartFilenameInvalid: The filename of the `fileURL` provided has either an empty
+ /// `lastPathComponent` or `pathExtension.
+ /// - bodyPartFileNotReachable: The file at the `fileURL` provided was not reachable.
+ /// - bodyPartFileNotReachableWithError: Attempting to check the reachability of the `fileURL` provided threw
+ /// an error.
+ /// - bodyPartFileIsDirectory: The file at the `fileURL` provided is actually a directory.
+ /// - bodyPartFileSizeNotAvailable: The size of the file at the `fileURL` provided was not returned by
+ /// the system.
+ /// - bodyPartFileSizeQueryFailedWithError: The attempt to find the size of the file at the `fileURL` provided
+ /// threw an error.
+ /// - bodyPartInputStreamCreationFailed: An `InputStream` could not be created for the provided `fileURL`.
+ /// - outputStreamCreationFailed: An `OutputStream` could not be created when attempting to write the
+ /// encoded data to disk.
+ /// - outputStreamFileAlreadyExists: The encoded body data could not be writtent disk because a file
+ /// already exists at the provided `fileURL`.
+ /// - outputStreamURLInvalid: The `fileURL` provided for writing the encoded body data to disk is
+ /// not a file URL.
+ /// - outputStreamWriteFailed: The attempt to write the encoded body data to disk failed with an
+ /// underlying error.
+ /// - inputStreamReadFailed: The attempt to read an encoded body part `InputStream` failed with
+ /// underlying system error.
+ public enum MultipartEncodingFailureReason {
+ case bodyPartURLInvalid(url: URL)
+ case bodyPartFilenameInvalid(in: URL)
+ case bodyPartFileNotReachable(at: URL)
+ case bodyPartFileNotReachableWithError(atURL: URL, error: Error)
+ case bodyPartFileIsDirectory(at: URL)
+ case bodyPartFileSizeNotAvailable(at: URL)
+ case bodyPartFileSizeQueryFailedWithError(forURL: URL, error: Error)
+ case bodyPartInputStreamCreationFailed(for: URL)
+
+ case outputStreamCreationFailed(for: URL)
+ case outputStreamFileAlreadyExists(at: URL)
+ case outputStreamURLInvalid(url: URL)
+ case outputStreamWriteFailed(error: Error)
+
+ case inputStreamReadFailed(error: Error)
+ }
+
+ /// The underlying reason the response validation error occurred.
+ ///
+ /// - dataFileNil: The data file containing the server response did not exist.
+ /// - dataFileReadFailed: The data file containing the server response could not be read.
+ /// - missingContentType: The response did not contain a `Content-Type` and the `acceptableContentTypes`
+ /// provided did not contain wildcard type.
+ /// - unacceptableContentType: The response `Content-Type` did not match any type in the provided
+ /// `acceptableContentTypes`.
+ /// - unacceptableStatusCode: The response status code was not acceptable.
+ public enum ResponseValidationFailureReason {
+ case dataFileNil
+ case dataFileReadFailed(at: URL)
+ case missingContentType(acceptableContentTypes: [String])
+ case unacceptableContentType(acceptableContentTypes: [String], responseContentType: String)
+ case unacceptableStatusCode(code: Int)
+ }
+
+ /// The underlying reason the response serialization error occurred.
+ ///
+ /// - inputDataNil: The server response contained no data.
+ /// - inputDataNilOrZeroLength: The server response contained no data or the data was zero length.
+ /// - inputFileNil: The file containing the server response did not exist.
+ /// - inputFileReadFailed: The file containing the server response could not be read.
+ /// - stringSerializationFailed: String serialization failed using the provided `String.Encoding`.
+ /// - jsonSerializationFailed: JSON serialization failed with an underlying system error.
+ /// - propertyListSerializationFailed: Property list serialization failed with an underlying system error.
+ public enum ResponseSerializationFailureReason {
+ case inputDataNil
+ case inputDataNilOrZeroLength
+ case inputFileNil
+ case inputFileReadFailed(at: URL)
+ case stringSerializationFailed(encoding: String.Encoding)
+ case jsonSerializationFailed(error: Error)
+ case propertyListSerializationFailed(error: Error)
+ }
+
+ case invalidURL(url: URLConvertible)
+ case parameterEncodingFailed(reason: ParameterEncodingFailureReason)
+ case multipartEncodingFailed(reason: MultipartEncodingFailureReason)
+ case responseValidationFailed(reason: ResponseValidationFailureReason)
+ case responseSerializationFailed(reason: ResponseSerializationFailureReason)
+}
+
+// MARK: - Adapt Error
+
+struct AdaptError: Error {
+ let error: Error
+}
+
+extension Error {
+ var underlyingAdaptError: Error? { return (self as? AdaptError)?.error }
+}
+
+// MARK: - Error Booleans
+
+extension AFError {
+ /// Returns whether the AFError is an invalid URL error.
+ public var isInvalidURLError: Bool {
+ if case .invalidURL = self { return true }
+ return false
+ }
+
+ /// Returns whether the AFError is a parameter encoding error. When `true`, the `underlyingError` property will
+ /// contain the associated value.
+ public var isParameterEncodingError: Bool {
+ if case .parameterEncodingFailed = self { return true }
+ return false
+ }
+
+ /// Returns whether the AFError is a multipart encoding error. When `true`, the `url` and `underlyingError` properties
+ /// will contain the associated values.
+ public var isMultipartEncodingError: Bool {
+ if case .multipartEncodingFailed = self { return true }
+ return false
+ }
+
+ /// Returns whether the `AFError` is a response validation error. When `true`, the `acceptableContentTypes`,
+ /// `responseContentType`, and `responseCode` properties will contain the associated values.
+ public var isResponseValidationError: Bool {
+ if case .responseValidationFailed = self { return true }
+ return false
+ }
+
+ /// Returns whether the `AFError` is a response serialization error. When `true`, the `failedStringEncoding` and
+ /// `underlyingError` properties will contain the associated values.
+ public var isResponseSerializationError: Bool {
+ if case .responseSerializationFailed = self { return true }
+ return false
+ }
+}
+
+// MARK: - Convenience Properties
+
+extension AFError {
+ /// The `URLConvertible` associated with the error.
+ public var urlConvertible: URLConvertible? {
+ switch self {
+ case .invalidURL(let url):
+ return url
+ default:
+ return nil
+ }
+ }
+
+ /// The `URL` associated with the error.
+ public var url: URL? {
+ switch self {
+ case .multipartEncodingFailed(let reason):
+ return reason.url
+ default:
+ return nil
+ }
+ }
+
+ /// The `Error` returned by a system framework associated with a `.parameterEncodingFailed`,
+ /// `.multipartEncodingFailed` or `.responseSerializationFailed` error.
+ public var underlyingError: Error? {
+ switch self {
+ case .parameterEncodingFailed(let reason):
+ return reason.underlyingError
+ case .multipartEncodingFailed(let reason):
+ return reason.underlyingError
+ case .responseSerializationFailed(let reason):
+ return reason.underlyingError
+ default:
+ return nil
+ }
+ }
+
+ /// The acceptable `Content-Type`s of a `.responseValidationFailed` error.
+ public var acceptableContentTypes: [String]? {
+ switch self {
+ case .responseValidationFailed(let reason):
+ return reason.acceptableContentTypes
+ default:
+ return nil
+ }
+ }
+
+ /// The response `Content-Type` of a `.responseValidationFailed` error.
+ public var responseContentType: String? {
+ switch self {
+ case .responseValidationFailed(let reason):
+ return reason.responseContentType
+ default:
+ return nil
+ }
+ }
+
+ /// The response code of a `.responseValidationFailed` error.
+ public var responseCode: Int? {
+ switch self {
+ case .responseValidationFailed(let reason):
+ return reason.responseCode
+ default:
+ return nil
+ }
+ }
+
+ /// The `String.Encoding` associated with a failed `.stringResponse()` call.
+ public var failedStringEncoding: String.Encoding? {
+ switch self {
+ case .responseSerializationFailed(let reason):
+ return reason.failedStringEncoding
+ default:
+ return nil
+ }
+ }
+}
+
+extension AFError.ParameterEncodingFailureReason {
+ var underlyingError: Error? {
+ switch self {
+ case .jsonEncodingFailed(let error), .propertyListEncodingFailed(let error):
+ return error
+ default:
+ return nil
+ }
+ }
+}
+
+extension AFError.MultipartEncodingFailureReason {
+ var url: URL? {
+ switch self {
+ case .bodyPartURLInvalid(let url), .bodyPartFilenameInvalid(let url), .bodyPartFileNotReachable(let url),
+ .bodyPartFileIsDirectory(let url), .bodyPartFileSizeNotAvailable(let url),
+ .bodyPartInputStreamCreationFailed(let url), .outputStreamCreationFailed(let url),
+ .outputStreamFileAlreadyExists(let url), .outputStreamURLInvalid(let url),
+ .bodyPartFileNotReachableWithError(let url, _), .bodyPartFileSizeQueryFailedWithError(let url, _):
+ return url
+ default:
+ return nil
+ }
+ }
+
+ var underlyingError: Error? {
+ switch self {
+ case .bodyPartFileNotReachableWithError(_, let error), .bodyPartFileSizeQueryFailedWithError(_, let error),
+ .outputStreamWriteFailed(let error), .inputStreamReadFailed(let error):
+ return error
+ default:
+ return nil
+ }
+ }
+}
+
+extension AFError.ResponseValidationFailureReason {
+ var acceptableContentTypes: [String]? {
+ switch self {
+ case .missingContentType(let types), .unacceptableContentType(let types, _):
+ return types
+ default:
+ return nil
+ }
+ }
+
+ var responseContentType: String? {
+ switch self {
+ case .unacceptableContentType(_, let responseType):
+ return responseType
+ default:
+ return nil
+ }
+ }
+
+ var responseCode: Int? {
+ switch self {
+ case .unacceptableStatusCode(let code):
+ return code
+ default:
+ return nil
+ }
+ }
+}
+
+extension AFError.ResponseSerializationFailureReason {
+ var failedStringEncoding: String.Encoding? {
+ switch self {
+ case .stringSerializationFailed(let encoding):
+ return encoding
+ default:
+ return nil
+ }
+ }
+
+ var underlyingError: Error? {
+ switch self {
+ case .jsonSerializationFailed(let error), .propertyListSerializationFailed(let error):
+ return error
+ default:
+ return nil
+ }
+ }
+}
+
+// MARK: - Error Descriptions
+
+extension AFError: LocalizedError {
+ public var errorDescription: String? {
+ switch self {
+ case .invalidURL(let url):
+ return "URL is not valid: \(url)"
+ case .parameterEncodingFailed(let reason):
+ return reason.localizedDescription
+ case .multipartEncodingFailed(let reason):
+ return reason.localizedDescription
+ case .responseValidationFailed(let reason):
+ return reason.localizedDescription
+ case .responseSerializationFailed(let reason):
+ return reason.localizedDescription
+ }
+ }
+}
+
+extension AFError.ParameterEncodingFailureReason {
+ var localizedDescription: String {
+ switch self {
+ case .missingURL:
+ return "URL request to encode was missing a URL"
+ case .jsonEncodingFailed(let error):
+ return "JSON could not be encoded because of error:\n\(error.localizedDescription)"
+ case .propertyListEncodingFailed(let error):
+ return "PropertyList could not be encoded because of error:\n\(error.localizedDescription)"
+ }
+ }
+}
+
+extension AFError.MultipartEncodingFailureReason {
+ var localizedDescription: String {
+ switch self {
+ case .bodyPartURLInvalid(let url):
+ return "The URL provided is not a file URL: \(url)"
+ case .bodyPartFilenameInvalid(let url):
+ return "The URL provided does not have a valid filename: \(url)"
+ case .bodyPartFileNotReachable(let url):
+ return "The URL provided is not reachable: \(url)"
+ case .bodyPartFileNotReachableWithError(let url, let error):
+ return (
+ "The system returned an error while checking the provided URL for " +
+ "reachability.\nURL: \(url)\nError: \(error)"
+ )
+ case .bodyPartFileIsDirectory(let url):
+ return "The URL provided is a directory: \(url)"
+ case .bodyPartFileSizeNotAvailable(let url):
+ return "Could not fetch the file size from the provided URL: \(url)"
+ case .bodyPartFileSizeQueryFailedWithError(let url, let error):
+ return (
+ "The system returned an error while attempting to fetch the file size from the " +
+ "provided URL.\nURL: \(url)\nError: \(error)"
+ )
+ case .bodyPartInputStreamCreationFailed(let url):
+ return "Failed to create an InputStream for the provided URL: \(url)"
+ case .outputStreamCreationFailed(let url):
+ return "Failed to create an OutputStream for URL: \(url)"
+ case .outputStreamFileAlreadyExists(let url):
+ return "A file already exists at the provided URL: \(url)"
+ case .outputStreamURLInvalid(let url):
+ return "The provided OutputStream URL is invalid: \(url)"
+ case .outputStreamWriteFailed(let error):
+ return "OutputStream write failed with error: \(error)"
+ case .inputStreamReadFailed(let error):
+ return "InputStream read failed with error: \(error)"
+ }
+ }
+}
+
+extension AFError.ResponseSerializationFailureReason {
+ var localizedDescription: String {
+ switch self {
+ case .inputDataNil:
+ return "Response could not be serialized, input data was nil."
+ case .inputDataNilOrZeroLength:
+ return "Response could not be serialized, input data was nil or zero length."
+ case .inputFileNil:
+ return "Response could not be serialized, input file was nil."
+ case .inputFileReadFailed(let url):
+ return "Response could not be serialized, input file could not be read: \(url)."
+ case .stringSerializationFailed(let encoding):
+ return "String could not be serialized with encoding: \(encoding)."
+ case .jsonSerializationFailed(let error):
+ return "JSON could not be serialized because of error:\n\(error.localizedDescription)"
+ case .propertyListSerializationFailed(let error):
+ return "PropertyList could not be serialized because of error:\n\(error.localizedDescription)"
+ }
+ }
+}
+
+extension AFError.ResponseValidationFailureReason {
+ var localizedDescription: String {
+ switch self {
+ case .dataFileNil:
+ return "Response could not be validated, data file was nil."
+ case .dataFileReadFailed(let url):
+ return "Response could not be validated, data file could not be read: \(url)."
+ case .missingContentType(let types):
+ return (
+ "Response Content-Type was missing and acceptable content types " +
+ "(\(types.joined(separator: ","))) do not match \"*/*\"."
+ )
+ case .unacceptableContentType(let acceptableTypes, let responseType):
+ return (
+ "Response Content-Type \"\(responseType)\" does not match any acceptable types: " +
+ "\(acceptableTypes.joined(separator: ","))."
+ )
+ case .unacceptableStatusCode(let code):
+ return "Response status code was unacceptable: \(code)."
+ }
+ }
+}
diff --git a/Pods/Alamofire/Source/Alamofire.swift b/Pods/Alamofire/Source/Alamofire.swift
new file mode 100644
index 0000000..20c3672
--- /dev/null
+++ b/Pods/Alamofire/Source/Alamofire.swift
@@ -0,0 +1,465 @@
+//
+// Alamofire.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// Types adopting the `URLConvertible` protocol can be used to construct URLs, which are then used to construct
+/// URL requests.
+public protocol URLConvertible {
+ /// Returns a URL that conforms to RFC 2396 or throws an `Error`.
+ ///
+ /// - throws: An `Error` if the type cannot be converted to a `URL`.
+ ///
+ /// - returns: A URL or throws an `Error`.
+ func asURL() throws -> URL
+}
+
+extension String: URLConvertible {
+ /// Returns a URL if `self` represents a valid URL string that conforms to RFC 2396 or throws an `AFError`.
+ ///
+ /// - throws: An `AFError.invalidURL` if `self` is not a valid URL string.
+ ///
+ /// - returns: A URL or throws an `AFError`.
+ public func asURL() throws -> URL {
+ guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) }
+ return url
+ }
+}
+
+extension URL: URLConvertible {
+ /// Returns self.
+ public func asURL() throws -> URL { return self }
+}
+
+extension URLComponents: URLConvertible {
+ /// Returns a URL if `url` is not nil, otherwise throws an `Error`.
+ ///
+ /// - throws: An `AFError.invalidURL` if `url` is `nil`.
+ ///
+ /// - returns: A URL or throws an `AFError`.
+ public func asURL() throws -> URL {
+ guard let url = url else { throw AFError.invalidURL(url: self) }
+ return url
+ }
+}
+
+// MARK: -
+
+/// Types adopting the `URLRequestConvertible` protocol can be used to construct URL requests.
+public protocol URLRequestConvertible {
+ /// Returns a URL request or throws if an `Error` was encountered.
+ ///
+ /// - throws: An `Error` if the underlying `URLRequest` is `nil`.
+ ///
+ /// - returns: A URL request.
+ func asURLRequest() throws -> URLRequest
+}
+
+extension URLRequestConvertible {
+ /// The URL request.
+ public var urlRequest: URLRequest? { return try? asURLRequest() }
+}
+
+extension URLRequest: URLRequestConvertible {
+ /// Returns a URL request or throws if an `Error` was encountered.
+ public func asURLRequest() throws -> URLRequest { return self }
+}
+
+// MARK: -
+
+extension URLRequest {
+ /// Creates an instance with the specified `method`, `urlString` and `headers`.
+ ///
+ /// - parameter url: The URL.
+ /// - parameter method: The HTTP method.
+ /// - parameter headers: The HTTP headers. `nil` by default.
+ ///
+ /// - returns: The new `URLRequest` instance.
+ public init(url: URLConvertible, method: HTTPMethod, headers: HTTPHeaders? = nil) throws {
+ let url = try url.asURL()
+
+ self.init(url: url)
+
+ httpMethod = method.rawValue
+
+ if let headers = headers {
+ for (headerField, headerValue) in headers {
+ setValue(headerValue, forHTTPHeaderField: headerField)
+ }
+ }
+ }
+
+ func adapt(using adapter: RequestAdapter?) throws -> URLRequest {
+ guard let adapter = adapter else { return self }
+ return try adapter.adapt(self)
+ }
+}
+
+// MARK: - Data Request
+
+/// Creates a `DataRequest` using the default `SessionManager` to retrieve the contents of the specified `url`,
+/// `method`, `parameters`, `encoding` and `headers`.
+///
+/// - parameter url: The URL.
+/// - parameter method: The HTTP method. `.get` by default.
+/// - parameter parameters: The parameters. `nil` by default.
+/// - parameter encoding: The parameter encoding. `URLEncoding.default` by default.
+/// - parameter headers: The HTTP headers. `nil` by default.
+///
+/// - returns: The created `DataRequest`.
+@discardableResult
+public func request(
+ _ url: URLConvertible,
+ method: HTTPMethod = .get,
+ parameters: Parameters? = nil,
+ encoding: ParameterEncoding = URLEncoding.default,
+ headers: HTTPHeaders? = nil)
+ -> DataRequest
+{
+ return SessionManager.default.request(
+ url,
+ method: method,
+ parameters: parameters,
+ encoding: encoding,
+ headers: headers
+ )
+}
+
+/// Creates a `DataRequest` using the default `SessionManager` to retrieve the contents of a URL based on the
+/// specified `urlRequest`.
+///
+/// - parameter urlRequest: The URL request
+///
+/// - returns: The created `DataRequest`.
+@discardableResult
+public func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
+ return SessionManager.default.request(urlRequest)
+}
+
+// MARK: - Download Request
+
+// MARK: URL Request
+
+/// Creates a `DownloadRequest` using the default `SessionManager` to retrieve the contents of the specified `url`,
+/// `method`, `parameters`, `encoding`, `headers` and save them to the `destination`.
+///
+/// If `destination` is not specified, the contents will remain in the temporary location determined by the
+/// underlying URL session.
+///
+/// - parameter url: The URL.
+/// - parameter method: The HTTP method. `.get` by default.
+/// - parameter parameters: The parameters. `nil` by default.
+/// - parameter encoding: The parameter encoding. `URLEncoding.default` by default.
+/// - parameter headers: The HTTP headers. `nil` by default.
+/// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default.
+///
+/// - returns: The created `DownloadRequest`.
+@discardableResult
+public func download(
+ _ url: URLConvertible,
+ method: HTTPMethod = .get,
+ parameters: Parameters? = nil,
+ encoding: ParameterEncoding = URLEncoding.default,
+ headers: HTTPHeaders? = nil,
+ to destination: DownloadRequest.DownloadFileDestination? = nil)
+ -> DownloadRequest
+{
+ return SessionManager.default.download(
+ url,
+ method: method,
+ parameters: parameters,
+ encoding: encoding,
+ headers: headers,
+ to: destination
+ )
+}
+
+/// Creates a `DownloadRequest` using the default `SessionManager` to retrieve the contents of a URL based on the
+/// specified `urlRequest` and save them to the `destination`.
+///
+/// If `destination` is not specified, the contents will remain in the temporary location determined by the
+/// underlying URL session.
+///
+/// - parameter urlRequest: The URL request.
+/// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default.
+///
+/// - returns: The created `DownloadRequest`.
+@discardableResult
+public func download(
+ _ urlRequest: URLRequestConvertible,
+ to destination: DownloadRequest.DownloadFileDestination? = nil)
+ -> DownloadRequest
+{
+ return SessionManager.default.download(urlRequest, to: destination)
+}
+
+// MARK: Resume Data
+
+/// Creates a `DownloadRequest` using the default `SessionManager` from the `resumeData` produced from a
+/// previous request cancellation to retrieve the contents of the original request and save them to the `destination`.
+///
+/// If `destination` is not specified, the contents will remain in the temporary location determined by the
+/// underlying URL session.
+///
+/// On the latest release of all the Apple platforms (iOS 10, macOS 10.12, tvOS 10, watchOS 3), `resumeData` is broken
+/// on background URL session configurations. There's an underlying bug in the `resumeData` generation logic where the
+/// data is written incorrectly and will always fail to resume the download. For more information about the bug and
+/// possible workarounds, please refer to the following Stack Overflow post:
+///
+/// - http://stackoverflow.com/a/39347461/1342462
+///
+/// - parameter resumeData: The resume data. This is an opaque data blob produced by `URLSessionDownloadTask`
+/// when a task is cancelled. See `URLSession -downloadTask(withResumeData:)` for additional
+/// information.
+/// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default.
+///
+/// - returns: The created `DownloadRequest`.
+@discardableResult
+public func download(
+ resumingWith resumeData: Data,
+ to destination: DownloadRequest.DownloadFileDestination? = nil)
+ -> DownloadRequest
+{
+ return SessionManager.default.download(resumingWith: resumeData, to: destination)
+}
+
+// MARK: - Upload Request
+
+// MARK: File
+
+/// Creates an `UploadRequest` using the default `SessionManager` from the specified `url`, `method` and `headers`
+/// for uploading the `file`.
+///
+/// - parameter file: The file to upload.
+/// - parameter url: The URL.
+/// - parameter method: The HTTP method. `.post` by default.
+/// - parameter headers: The HTTP headers. `nil` by default.
+///
+/// - returns: The created `UploadRequest`.
+@discardableResult
+public func upload(
+ _ fileURL: URL,
+ to url: URLConvertible,
+ method: HTTPMethod = .post,
+ headers: HTTPHeaders? = nil)
+ -> UploadRequest
+{
+ return SessionManager.default.upload(fileURL, to: url, method: method, headers: headers)
+}
+
+/// Creates a `UploadRequest` using the default `SessionManager` from the specified `urlRequest` for
+/// uploading the `file`.
+///
+/// - parameter file: The file to upload.
+/// - parameter urlRequest: The URL request.
+///
+/// - returns: The created `UploadRequest`.
+@discardableResult
+public func upload(_ fileURL: URL, with urlRequest: URLRequestConvertible) -> UploadRequest {
+ return SessionManager.default.upload(fileURL, with: urlRequest)
+}
+
+// MARK: Data
+
+/// Creates an `UploadRequest` using the default `SessionManager` from the specified `url`, `method` and `headers`
+/// for uploading the `data`.
+///
+/// - parameter data: The data to upload.
+/// - parameter url: The URL.
+/// - parameter method: The HTTP method. `.post` by default.
+/// - parameter headers: The HTTP headers. `nil` by default.
+///
+/// - returns: The created `UploadRequest`.
+@discardableResult
+public func upload(
+ _ data: Data,
+ to url: URLConvertible,
+ method: HTTPMethod = .post,
+ headers: HTTPHeaders? = nil)
+ -> UploadRequest
+{
+ return SessionManager.default.upload(data, to: url, method: method, headers: headers)
+}
+
+/// Creates an `UploadRequest` using the default `SessionManager` from the specified `urlRequest` for
+/// uploading the `data`.
+///
+/// - parameter data: The data to upload.
+/// - parameter urlRequest: The URL request.
+///
+/// - returns: The created `UploadRequest`.
+@discardableResult
+public func upload(_ data: Data, with urlRequest: URLRequestConvertible) -> UploadRequest {
+ return SessionManager.default.upload(data, with: urlRequest)
+}
+
+// MARK: InputStream
+
+/// Creates an `UploadRequest` using the default `SessionManager` from the specified `url`, `method` and `headers`
+/// for uploading the `stream`.
+///
+/// - parameter stream: The stream to upload.
+/// - parameter url: The URL.
+/// - parameter method: The HTTP method. `.post` by default.
+/// - parameter headers: The HTTP headers. `nil` by default.
+///
+/// - returns: The created `UploadRequest`.
+@discardableResult
+public func upload(
+ _ stream: InputStream,
+ to url: URLConvertible,
+ method: HTTPMethod = .post,
+ headers: HTTPHeaders? = nil)
+ -> UploadRequest
+{
+ return SessionManager.default.upload(stream, to: url, method: method, headers: headers)
+}
+
+/// Creates an `UploadRequest` using the default `SessionManager` from the specified `urlRequest` for
+/// uploading the `stream`.
+///
+/// - parameter urlRequest: The URL request.
+/// - parameter stream: The stream to upload.
+///
+/// - returns: The created `UploadRequest`.
+@discardableResult
+public func upload(_ stream: InputStream, with urlRequest: URLRequestConvertible) -> UploadRequest {
+ return SessionManager.default.upload(stream, with: urlRequest)
+}
+
+// MARK: MultipartFormData
+
+/// Encodes `multipartFormData` using `encodingMemoryThreshold` with the default `SessionManager` and calls
+/// `encodingCompletion` with new `UploadRequest` using the `url`, `method` and `headers`.
+///
+/// It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative
+/// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
+/// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
+/// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
+/// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
+/// used for larger payloads such as video content.
+///
+/// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
+/// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
+/// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
+/// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
+/// technique was used.
+///
+/// - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
+/// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes.
+/// `multipartFormDataEncodingMemoryThreshold` by default.
+/// - parameter url: The URL.
+/// - parameter method: The HTTP method. `.post` by default.
+/// - parameter headers: The HTTP headers. `nil` by default.
+/// - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
+public func upload(
+ multipartFormData: @escaping (MultipartFormData) -> Void,
+ usingThreshold encodingMemoryThreshold: UInt64 = SessionManager.multipartFormDataEncodingMemoryThreshold,
+ to url: URLConvertible,
+ method: HTTPMethod = .post,
+ headers: HTTPHeaders? = nil,
+ encodingCompletion: ((SessionManager.MultipartFormDataEncodingResult) -> Void)?)
+{
+ return SessionManager.default.upload(
+ multipartFormData: multipartFormData,
+ usingThreshold: encodingMemoryThreshold,
+ to: url,
+ method: method,
+ headers: headers,
+ encodingCompletion: encodingCompletion
+ )
+}
+
+/// Encodes `multipartFormData` using `encodingMemoryThreshold` and the default `SessionManager` and
+/// calls `encodingCompletion` with new `UploadRequest` using the `urlRequest`.
+///
+/// It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative
+/// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
+/// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
+/// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
+/// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
+/// used for larger payloads such as video content.
+///
+/// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
+/// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
+/// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
+/// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
+/// technique was used.
+///
+/// - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
+/// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes.
+/// `multipartFormDataEncodingMemoryThreshold` by default.
+/// - parameter urlRequest: The URL request.
+/// - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
+public func upload(
+ multipartFormData: @escaping (MultipartFormData) -> Void,
+ usingThreshold encodingMemoryThreshold: UInt64 = SessionManager.multipartFormDataEncodingMemoryThreshold,
+ with urlRequest: URLRequestConvertible,
+ encodingCompletion: ((SessionManager.MultipartFormDataEncodingResult) -> Void)?)
+{
+ return SessionManager.default.upload(
+ multipartFormData: multipartFormData,
+ usingThreshold: encodingMemoryThreshold,
+ with: urlRequest,
+ encodingCompletion: encodingCompletion
+ )
+}
+
+#if !os(watchOS)
+
+// MARK: - Stream Request
+
+// MARK: Hostname and Port
+
+/// Creates a `StreamRequest` using the default `SessionManager` for bidirectional streaming with the `hostname`
+/// and `port`.
+///
+/// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+///
+/// - parameter hostName: The hostname of the server to connect to.
+/// - parameter port: The port of the server to connect to.
+///
+/// - returns: The created `StreamRequest`.
+@discardableResult
+@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+public func stream(withHostName hostName: String, port: Int) -> StreamRequest {
+ return SessionManager.default.stream(withHostName: hostName, port: port)
+}
+
+// MARK: NetService
+
+/// Creates a `StreamRequest` using the default `SessionManager` for bidirectional streaming with the `netService`.
+///
+/// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+///
+/// - parameter netService: The net service used to identify the endpoint.
+///
+/// - returns: The created `StreamRequest`.
+@discardableResult
+@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+public func stream(with netService: NetService) -> StreamRequest {
+ return SessionManager.default.stream(with: netService)
+}
+
+#endif
diff --git a/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift b/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift
new file mode 100644
index 0000000..a54673c
--- /dev/null
+++ b/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift
@@ -0,0 +1,37 @@
+//
+// DispatchQueue+Alamofire.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Dispatch
+import Foundation
+
+extension DispatchQueue {
+ static var userInteractive: DispatchQueue { return DispatchQueue.global(qos: .userInteractive) }
+ static var userInitiated: DispatchQueue { return DispatchQueue.global(qos: .userInitiated) }
+ static var utility: DispatchQueue { return DispatchQueue.global(qos: .utility) }
+ static var background: DispatchQueue { return DispatchQueue.global(qos: .background) }
+
+ func after(_ delay: TimeInterval, execute closure: @escaping () -> Void) {
+ asyncAfter(deadline: .now() + delay, execute: closure)
+ }
+}
diff --git a/Pods/Alamofire/Source/MultipartFormData.swift b/Pods/Alamofire/Source/MultipartFormData.swift
new file mode 100644
index 0000000..b840138
--- /dev/null
+++ b/Pods/Alamofire/Source/MultipartFormData.swift
@@ -0,0 +1,580 @@
+//
+// MultipartFormData.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+#if os(iOS) || os(watchOS) || os(tvOS)
+import MobileCoreServices
+#elseif os(macOS)
+import CoreServices
+#endif
+
+/// Constructs `multipart/form-data` for uploads within an HTTP or HTTPS body. There are currently two ways to encode
+/// multipart form data. The first way is to encode the data directly in memory. This is very efficient, but can lead
+/// to memory issues if the dataset is too large. The second way is designed for larger datasets and will write all the
+/// data to a single file on disk with all the proper boundary segmentation. The second approach MUST be used for
+/// larger datasets such as video content, otherwise your app may run out of memory when trying to encode the dataset.
+///
+/// For more information on `multipart/form-data` in general, please refer to the RFC-2388 and RFC-2045 specs as well
+/// and the w3 form documentation.
+///
+/// - https://www.ietf.org/rfc/rfc2388.txt
+/// - https://www.ietf.org/rfc/rfc2045.txt
+/// - https://www.w3.org/TR/html401/interact/forms.html#h-17.13
+open class MultipartFormData {
+
+ // MARK: - Helper Types
+
+ struct EncodingCharacters {
+ static let crlf = "\r\n"
+ }
+
+ struct BoundaryGenerator {
+ enum BoundaryType {
+ case initial, encapsulated, final
+ }
+
+ static func randomBoundary() -> String {
+ return String(format: "alamofire.boundary.%08x%08x", arc4random(), arc4random())
+ }
+
+ static func boundaryData(forBoundaryType boundaryType: BoundaryType, boundary: String) -> Data {
+ let boundaryText: String
+
+ switch boundaryType {
+ case .initial:
+ boundaryText = "--\(boundary)\(EncodingCharacters.crlf)"
+ case .encapsulated:
+ boundaryText = "\(EncodingCharacters.crlf)--\(boundary)\(EncodingCharacters.crlf)"
+ case .final:
+ boundaryText = "\(EncodingCharacters.crlf)--\(boundary)--\(EncodingCharacters.crlf)"
+ }
+
+ return boundaryText.data(using: String.Encoding.utf8, allowLossyConversion: false)!
+ }
+ }
+
+ class BodyPart {
+ let headers: HTTPHeaders
+ let bodyStream: InputStream
+ let bodyContentLength: UInt64
+ var hasInitialBoundary = false
+ var hasFinalBoundary = false
+
+ init(headers: HTTPHeaders, bodyStream: InputStream, bodyContentLength: UInt64) {
+ self.headers = headers
+ self.bodyStream = bodyStream
+ self.bodyContentLength = bodyContentLength
+ }
+ }
+
+ // MARK: - Properties
+
+ /// The `Content-Type` header value containing the boundary used to generate the `multipart/form-data`.
+ open lazy var contentType: String = "multipart/form-data; boundary=\(self.boundary)"
+
+ /// The content length of all body parts used to generate the `multipart/form-data` not including the boundaries.
+ public var contentLength: UInt64 { return bodyParts.reduce(0) { $0 + $1.bodyContentLength } }
+
+ /// The boundary used to separate the body parts in the encoded form data.
+ public var boundary: String
+
+ private var bodyParts: [BodyPart]
+ private var bodyPartError: AFError?
+ private let streamBufferSize: Int
+
+ // MARK: - Lifecycle
+
+ /// Creates a multipart form data object.
+ ///
+ /// - returns: The multipart form data object.
+ public init() {
+ self.boundary = BoundaryGenerator.randomBoundary()
+ self.bodyParts = []
+
+ ///
+ /// The optimal read/write buffer size in bytes for input and output streams is 1024 (1KB). For more
+ /// information, please refer to the following article:
+ /// - https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html
+ ///
+
+ self.streamBufferSize = 1024
+ }
+
+ // MARK: - Body Parts
+
+ /// Creates a body part from the data and appends it to the multipart form data object.
+ ///
+ /// The body part data will be encoded using the following format:
+ ///
+ /// - `Content-Disposition: form-data; name=#{name}` (HTTP Header)
+ /// - Encoded data
+ /// - Multipart form boundary
+ ///
+ /// - parameter data: The data to encode into the multipart form data.
+ /// - parameter name: The name to associate with the data in the `Content-Disposition` HTTP header.
+ public func append(_ data: Data, withName name: String) {
+ let headers = contentHeaders(withName: name)
+ let stream = InputStream(data: data)
+ let length = UInt64(data.count)
+
+ append(stream, withLength: length, headers: headers)
+ }
+
+ /// Creates a body part from the data and appends it to the multipart form data object.
+ ///
+ /// The body part data will be encoded using the following format:
+ ///
+ /// - `Content-Disposition: form-data; name=#{name}` (HTTP Header)
+ /// - `Content-Type: #{generated mimeType}` (HTTP Header)
+ /// - Encoded data
+ /// - Multipart form boundary
+ ///
+ /// - parameter data: The data to encode into the multipart form data.
+ /// - parameter name: The name to associate with the data in the `Content-Disposition` HTTP header.
+ /// - parameter mimeType: The MIME type to associate with the data content type in the `Content-Type` HTTP header.
+ public func append(_ data: Data, withName name: String, mimeType: String) {
+ let headers = contentHeaders(withName: name, mimeType: mimeType)
+ let stream = InputStream(data: data)
+ let length = UInt64(data.count)
+
+ append(stream, withLength: length, headers: headers)
+ }
+
+ /// Creates a body part from the data and appends it to the multipart form data object.
+ ///
+ /// The body part data will be encoded using the following format:
+ ///
+ /// - `Content-Disposition: form-data; name=#{name}; filename=#{filename}` (HTTP Header)
+ /// - `Content-Type: #{mimeType}` (HTTP Header)
+ /// - Encoded file data
+ /// - Multipart form boundary
+ ///
+ /// - parameter data: The data to encode into the multipart form data.
+ /// - parameter name: The name to associate with the data in the `Content-Disposition` HTTP header.
+ /// - parameter fileName: The filename to associate with the data in the `Content-Disposition` HTTP header.
+ /// - parameter mimeType: The MIME type to associate with the data in the `Content-Type` HTTP header.
+ public func append(_ data: Data, withName name: String, fileName: String, mimeType: String) {
+ let headers = contentHeaders(withName: name, fileName: fileName, mimeType: mimeType)
+ let stream = InputStream(data: data)
+ let length = UInt64(data.count)
+
+ append(stream, withLength: length, headers: headers)
+ }
+
+ /// Creates a body part from the file and appends it to the multipart form data object.
+ ///
+ /// The body part data will be encoded using the following format:
+ ///
+ /// - `Content-Disposition: form-data; name=#{name}; filename=#{generated filename}` (HTTP Header)
+ /// - `Content-Type: #{generated mimeType}` (HTTP Header)
+ /// - Encoded file data
+ /// - Multipart form boundary
+ ///
+ /// The filename in the `Content-Disposition` HTTP header is generated from the last path component of the
+ /// `fileURL`. The `Content-Type` HTTP header MIME type is generated by mapping the `fileURL` extension to the
+ /// system associated MIME type.
+ ///
+ /// - parameter fileURL: The URL of the file whose content will be encoded into the multipart form data.
+ /// - parameter name: The name to associate with the file content in the `Content-Disposition` HTTP header.
+ public func append(_ fileURL: URL, withName name: String) {
+ let fileName = fileURL.lastPathComponent
+ let pathExtension = fileURL.pathExtension
+
+ if !fileName.isEmpty && !pathExtension.isEmpty {
+ let mime = mimeType(forPathExtension: pathExtension)
+ append(fileURL, withName: name, fileName: fileName, mimeType: mime)
+ } else {
+ setBodyPartError(withReason: .bodyPartFilenameInvalid(in: fileURL))
+ }
+ }
+
+ /// Creates a body part from the file and appends it to the multipart form data object.
+ ///
+ /// The body part data will be encoded using the following format:
+ ///
+ /// - Content-Disposition: form-data; name=#{name}; filename=#{filename} (HTTP Header)
+ /// - Content-Type: #{mimeType} (HTTP Header)
+ /// - Encoded file data
+ /// - Multipart form boundary
+ ///
+ /// - parameter fileURL: The URL of the file whose content will be encoded into the multipart form data.
+ /// - parameter name: The name to associate with the file content in the `Content-Disposition` HTTP header.
+ /// - parameter fileName: The filename to associate with the file content in the `Content-Disposition` HTTP header.
+ /// - parameter mimeType: The MIME type to associate with the file content in the `Content-Type` HTTP header.
+ public func append(_ fileURL: URL, withName name: String, fileName: String, mimeType: String) {
+ let headers = contentHeaders(withName: name, fileName: fileName, mimeType: mimeType)
+
+ //============================================================
+ // Check 1 - is file URL?
+ //============================================================
+
+ guard fileURL.isFileURL else {
+ setBodyPartError(withReason: .bodyPartURLInvalid(url: fileURL))
+ return
+ }
+
+ //============================================================
+ // Check 2 - is file URL reachable?
+ //============================================================
+
+ do {
+ let isReachable = try fileURL.checkPromisedItemIsReachable()
+ guard isReachable else {
+ setBodyPartError(withReason: .bodyPartFileNotReachable(at: fileURL))
+ return
+ }
+ } catch {
+ setBodyPartError(withReason: .bodyPartFileNotReachableWithError(atURL: fileURL, error: error))
+ return
+ }
+
+ //============================================================
+ // Check 3 - is file URL a directory?
+ //============================================================
+
+ var isDirectory: ObjCBool = false
+ let path = fileURL.path
+
+ guard FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) && !isDirectory.boolValue else {
+ setBodyPartError(withReason: .bodyPartFileIsDirectory(at: fileURL))
+ return
+ }
+
+ //============================================================
+ // Check 4 - can the file size be extracted?
+ //============================================================
+
+ let bodyContentLength: UInt64
+
+ do {
+ guard let fileSize = try FileManager.default.attributesOfItem(atPath: path)[.size] as? NSNumber else {
+ setBodyPartError(withReason: .bodyPartFileSizeNotAvailable(at: fileURL))
+ return
+ }
+
+ bodyContentLength = fileSize.uint64Value
+ }
+ catch {
+ setBodyPartError(withReason: .bodyPartFileSizeQueryFailedWithError(forURL: fileURL, error: error))
+ return
+ }
+
+ //============================================================
+ // Check 5 - can a stream be created from file URL?
+ //============================================================
+
+ guard let stream = InputStream(url: fileURL) else {
+ setBodyPartError(withReason: .bodyPartInputStreamCreationFailed(for: fileURL))
+ return
+ }
+
+ append(stream, withLength: bodyContentLength, headers: headers)
+ }
+
+ /// Creates a body part from the stream and appends it to the multipart form data object.
+ ///
+ /// The body part data will be encoded using the following format:
+ ///
+ /// - `Content-Disposition: form-data; name=#{name}; filename=#{filename}` (HTTP Header)
+ /// - `Content-Type: #{mimeType}` (HTTP Header)
+ /// - Encoded stream data
+ /// - Multipart form boundary
+ ///
+ /// - parameter stream: The input stream to encode in the multipart form data.
+ /// - parameter length: The content length of the stream.
+ /// - parameter name: The name to associate with the stream content in the `Content-Disposition` HTTP header.
+ /// - parameter fileName: The filename to associate with the stream content in the `Content-Disposition` HTTP header.
+ /// - parameter mimeType: The MIME type to associate with the stream content in the `Content-Type` HTTP header.
+ public func append(
+ _ stream: InputStream,
+ withLength length: UInt64,
+ name: String,
+ fileName: String,
+ mimeType: String)
+ {
+ let headers = contentHeaders(withName: name, fileName: fileName, mimeType: mimeType)
+ append(stream, withLength: length, headers: headers)
+ }
+
+ /// Creates a body part with the headers, stream and length and appends it to the multipart form data object.
+ ///
+ /// The body part data will be encoded using the following format:
+ ///
+ /// - HTTP headers
+ /// - Encoded stream data
+ /// - Multipart form boundary
+ ///
+ /// - parameter stream: The input stream to encode in the multipart form data.
+ /// - parameter length: The content length of the stream.
+ /// - parameter headers: The HTTP headers for the body part.
+ public func append(_ stream: InputStream, withLength length: UInt64, headers: HTTPHeaders) {
+ let bodyPart = BodyPart(headers: headers, bodyStream: stream, bodyContentLength: length)
+ bodyParts.append(bodyPart)
+ }
+
+ // MARK: - Data Encoding
+
+ /// Encodes all the appended body parts into a single `Data` value.
+ ///
+ /// It is important to note that this method will load all the appended body parts into memory all at the same
+ /// time. This method should only be used when the encoded data will have a small memory footprint. For large data
+ /// cases, please use the `writeEncodedDataToDisk(fileURL:completionHandler:)` method.
+ ///
+ /// - throws: An `AFError` if encoding encounters an error.
+ ///
+ /// - returns: The encoded `Data` if encoding is successful.
+ public func encode() throws -> Data {
+ if let bodyPartError = bodyPartError {
+ throw bodyPartError
+ }
+
+ var encoded = Data()
+
+ bodyParts.first?.hasInitialBoundary = true
+ bodyParts.last?.hasFinalBoundary = true
+
+ for bodyPart in bodyParts {
+ let encodedData = try encode(bodyPart)
+ encoded.append(encodedData)
+ }
+
+ return encoded
+ }
+
+ /// Writes the appended body parts into the given file URL.
+ ///
+ /// This process is facilitated by reading and writing with input and output streams, respectively. Thus,
+ /// this approach is very memory efficient and should be used for large body part data.
+ ///
+ /// - parameter fileURL: The file URL to write the multipart form data into.
+ ///
+ /// - throws: An `AFError` if encoding encounters an error.
+ public func writeEncodedData(to fileURL: URL) throws {
+ if let bodyPartError = bodyPartError {
+ throw bodyPartError
+ }
+
+ if FileManager.default.fileExists(atPath: fileURL.path) {
+ throw AFError.multipartEncodingFailed(reason: .outputStreamFileAlreadyExists(at: fileURL))
+ } else if !fileURL.isFileURL {
+ throw AFError.multipartEncodingFailed(reason: .outputStreamURLInvalid(url: fileURL))
+ }
+
+ guard let outputStream = OutputStream(url: fileURL, append: false) else {
+ throw AFError.multipartEncodingFailed(reason: .outputStreamCreationFailed(for: fileURL))
+ }
+
+ outputStream.open()
+ defer { outputStream.close() }
+
+ self.bodyParts.first?.hasInitialBoundary = true
+ self.bodyParts.last?.hasFinalBoundary = true
+
+ for bodyPart in self.bodyParts {
+ try write(bodyPart, to: outputStream)
+ }
+ }
+
+ // MARK: - Private - Body Part Encoding
+
+ private func encode(_ bodyPart: BodyPart) throws -> Data {
+ var encoded = Data()
+
+ let initialData = bodyPart.hasInitialBoundary ? initialBoundaryData() : encapsulatedBoundaryData()
+ encoded.append(initialData)
+
+ let headerData = encodeHeaders(for: bodyPart)
+ encoded.append(headerData)
+
+ let bodyStreamData = try encodeBodyStream(for: bodyPart)
+ encoded.append(bodyStreamData)
+
+ if bodyPart.hasFinalBoundary {
+ encoded.append(finalBoundaryData())
+ }
+
+ return encoded
+ }
+
+ private func encodeHeaders(for bodyPart: BodyPart) -> Data {
+ var headerText = ""
+
+ for (key, value) in bodyPart.headers {
+ headerText += "\(key): \(value)\(EncodingCharacters.crlf)"
+ }
+ headerText += EncodingCharacters.crlf
+
+ return headerText.data(using: String.Encoding.utf8, allowLossyConversion: false)!
+ }
+
+ private func encodeBodyStream(for bodyPart: BodyPart) throws -> Data {
+ let inputStream = bodyPart.bodyStream
+ inputStream.open()
+ defer { inputStream.close() }
+
+ var encoded = Data()
+
+ while inputStream.hasBytesAvailable {
+ var buffer = [UInt8](repeating: 0, count: streamBufferSize)
+ let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize)
+
+ if let error = inputStream.streamError {
+ throw AFError.multipartEncodingFailed(reason: .inputStreamReadFailed(error: error))
+ }
+
+ if bytesRead > 0 {
+ encoded.append(buffer, count: bytesRead)
+ } else {
+ break
+ }
+ }
+
+ return encoded
+ }
+
+ // MARK: - Private - Writing Body Part to Output Stream
+
+ private func write(_ bodyPart: BodyPart, to outputStream: OutputStream) throws {
+ try writeInitialBoundaryData(for: bodyPart, to: outputStream)
+ try writeHeaderData(for: bodyPart, to: outputStream)
+ try writeBodyStream(for: bodyPart, to: outputStream)
+ try writeFinalBoundaryData(for: bodyPart, to: outputStream)
+ }
+
+ private func writeInitialBoundaryData(for bodyPart: BodyPart, to outputStream: OutputStream) throws {
+ let initialData = bodyPart.hasInitialBoundary ? initialBoundaryData() : encapsulatedBoundaryData()
+ return try write(initialData, to: outputStream)
+ }
+
+ private func writeHeaderData(for bodyPart: BodyPart, to outputStream: OutputStream) throws {
+ let headerData = encodeHeaders(for: bodyPart)
+ return try write(headerData, to: outputStream)
+ }
+
+ private func writeBodyStream(for bodyPart: BodyPart, to outputStream: OutputStream) throws {
+ let inputStream = bodyPart.bodyStream
+
+ inputStream.open()
+ defer { inputStream.close() }
+
+ while inputStream.hasBytesAvailable {
+ var buffer = [UInt8](repeating: 0, count: streamBufferSize)
+ let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize)
+
+ if let streamError = inputStream.streamError {
+ throw AFError.multipartEncodingFailed(reason: .inputStreamReadFailed(error: streamError))
+ }
+
+ if bytesRead > 0 {
+ if buffer.count != bytesRead {
+ buffer = Array(buffer[0.. 0, outputStream.hasSpaceAvailable {
+ let bytesWritten = outputStream.write(buffer, maxLength: bytesToWrite)
+
+ if let error = outputStream.streamError {
+ throw AFError.multipartEncodingFailed(reason: .outputStreamWriteFailed(error: error))
+ }
+
+ bytesToWrite -= bytesWritten
+
+ if bytesToWrite > 0 {
+ buffer = Array(buffer[bytesWritten.. String {
+ if
+ let id = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(),
+ let contentType = UTTypeCopyPreferredTagWithClass(id, kUTTagClassMIMEType)?.takeRetainedValue()
+ {
+ return contentType as String
+ }
+
+ return "application/octet-stream"
+ }
+
+ // MARK: - Private - Content Headers
+
+ private func contentHeaders(withName name: String, fileName: String? = nil, mimeType: String? = nil) -> [String: String] {
+ var disposition = "form-data; name=\"\(name)\""
+ if let fileName = fileName { disposition += "; filename=\"\(fileName)\"" }
+
+ var headers = ["Content-Disposition": disposition]
+ if let mimeType = mimeType { headers["Content-Type"] = mimeType }
+
+ return headers
+ }
+
+ // MARK: - Private - Boundary Encoding
+
+ private func initialBoundaryData() -> Data {
+ return BoundaryGenerator.boundaryData(forBoundaryType: .initial, boundary: boundary)
+ }
+
+ private func encapsulatedBoundaryData() -> Data {
+ return BoundaryGenerator.boundaryData(forBoundaryType: .encapsulated, boundary: boundary)
+ }
+
+ private func finalBoundaryData() -> Data {
+ return BoundaryGenerator.boundaryData(forBoundaryType: .final, boundary: boundary)
+ }
+
+ // MARK: - Private - Errors
+
+ private func setBodyPartError(withReason reason: AFError.MultipartEncodingFailureReason) {
+ guard bodyPartError == nil else { return }
+ bodyPartError = AFError.multipartEncodingFailed(reason: reason)
+ }
+}
diff --git a/Pods/Alamofire/Source/NetworkReachabilityManager.swift b/Pods/Alamofire/Source/NetworkReachabilityManager.swift
new file mode 100644
index 0000000..398ca82
--- /dev/null
+++ b/Pods/Alamofire/Source/NetworkReachabilityManager.swift
@@ -0,0 +1,238 @@
+//
+// NetworkReachabilityManager.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#if !os(watchOS)
+
+import Foundation
+import SystemConfiguration
+
+/// The `NetworkReachabilityManager` class listens for reachability changes of hosts and addresses for both WWAN and
+/// WiFi network interfaces.
+///
+/// Reachability can be used to determine background information about why a network operation failed, or to retry
+/// network requests when a connection is established. It should not be used to prevent a user from initiating a network
+/// request, as it's possible that an initial request may be required to establish reachability.
+open class NetworkReachabilityManager {
+ /// Defines the various states of network reachability.
+ ///
+ /// - unknown: It is unknown whether the network is reachable.
+ /// - notReachable: The network is not reachable.
+ /// - reachable: The network is reachable.
+ public enum NetworkReachabilityStatus {
+ case unknown
+ case notReachable
+ case reachable(ConnectionType)
+ }
+
+ /// Defines the various connection types detected by reachability flags.
+ ///
+ /// - ethernetOrWiFi: The connection type is either over Ethernet or WiFi.
+ /// - wwan: The connection type is a WWAN connection.
+ public enum ConnectionType {
+ case ethernetOrWiFi
+ case wwan
+ }
+
+ /// A closure executed when the network reachability status changes. The closure takes a single argument: the
+ /// network reachability status.
+ public typealias Listener = (NetworkReachabilityStatus) -> Void
+
+ // MARK: - Properties
+
+ /// Whether the network is currently reachable.
+ open var isReachable: Bool { return isReachableOnWWAN || isReachableOnEthernetOrWiFi }
+
+ /// Whether the network is currently reachable over the WWAN interface.
+ open var isReachableOnWWAN: Bool { return networkReachabilityStatus == .reachable(.wwan) }
+
+ /// Whether the network is currently reachable over Ethernet or WiFi interface.
+ open var isReachableOnEthernetOrWiFi: Bool { return networkReachabilityStatus == .reachable(.ethernetOrWiFi) }
+
+ /// The current network reachability status.
+ open var networkReachabilityStatus: NetworkReachabilityStatus {
+ guard let flags = self.flags else { return .unknown }
+ return networkReachabilityStatusForFlags(flags)
+ }
+
+ /// The dispatch queue to execute the `listener` closure on.
+ open var listenerQueue: DispatchQueue = DispatchQueue.main
+
+ /// A closure executed when the network reachability status changes.
+ open var listener: Listener?
+
+ open var flags: SCNetworkReachabilityFlags? {
+ var flags = SCNetworkReachabilityFlags()
+
+ if SCNetworkReachabilityGetFlags(reachability, &flags) {
+ return flags
+ }
+
+ return nil
+ }
+
+ private let reachability: SCNetworkReachability
+ open var previousFlags: SCNetworkReachabilityFlags
+
+ // MARK: - Initialization
+
+ /// Creates a `NetworkReachabilityManager` instance with the specified host.
+ ///
+ /// - parameter host: The host used to evaluate network reachability.
+ ///
+ /// - returns: The new `NetworkReachabilityManager` instance.
+ public convenience init?(host: String) {
+ guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else { return nil }
+ self.init(reachability: reachability)
+ }
+
+ /// Creates a `NetworkReachabilityManager` instance that monitors the address 0.0.0.0.
+ ///
+ /// Reachability treats the 0.0.0.0 address as a special token that causes it to monitor the general routing
+ /// status of the device, both IPv4 and IPv6.
+ ///
+ /// - returns: The new `NetworkReachabilityManager` instance.
+ public convenience init?() {
+ var address = sockaddr_in()
+ address.sin_len = UInt8(MemoryLayout.size)
+ address.sin_family = sa_family_t(AF_INET)
+
+ guard let reachability = withUnsafePointer(to: &address, { pointer in
+ return pointer.withMemoryRebound(to: sockaddr.self, capacity: MemoryLayout.size) {
+ return SCNetworkReachabilityCreateWithAddress(nil, $0)
+ }
+ }) else { return nil }
+
+ self.init(reachability: reachability)
+ }
+
+ private init(reachability: SCNetworkReachability) {
+ self.reachability = reachability
+
+ // Set the previous flags to an unreserved value to represent unknown status
+ self.previousFlags = SCNetworkReachabilityFlags(rawValue: 1 << 30)
+ }
+
+ deinit {
+ stopListening()
+ }
+
+ // MARK: - Listening
+
+ /// Starts listening for changes in network reachability status.
+ ///
+ /// - returns: `true` if listening was started successfully, `false` otherwise.
+ @discardableResult
+ open func startListening() -> Bool {
+ var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
+ context.info = Unmanaged.passUnretained(self).toOpaque()
+
+ let callbackEnabled = SCNetworkReachabilitySetCallback(
+ reachability,
+ { (_, flags, info) in
+ let reachability = Unmanaged.fromOpaque(info!).takeUnretainedValue()
+ reachability.notifyListener(flags)
+ },
+ &context
+ )
+
+ let queueEnabled = SCNetworkReachabilitySetDispatchQueue(reachability, listenerQueue)
+
+ listenerQueue.async {
+ self.previousFlags = SCNetworkReachabilityFlags(rawValue: 1 << 30)
+
+ guard let flags = self.flags else { return }
+
+ self.notifyListener(flags)
+ }
+
+ return callbackEnabled && queueEnabled
+ }
+
+ /// Stops listening for changes in network reachability status.
+ open func stopListening() {
+ SCNetworkReachabilitySetCallback(reachability, nil, nil)
+ SCNetworkReachabilitySetDispatchQueue(reachability, nil)
+ }
+
+ // MARK: - Internal - Listener Notification
+
+ func notifyListener(_ flags: SCNetworkReachabilityFlags) {
+ guard previousFlags != flags else { return }
+ previousFlags = flags
+
+ listener?(networkReachabilityStatusForFlags(flags))
+ }
+
+ // MARK: - Internal - Network Reachability Status
+
+ func networkReachabilityStatusForFlags(_ flags: SCNetworkReachabilityFlags) -> NetworkReachabilityStatus {
+ guard isNetworkReachable(with: flags) else { return .notReachable }
+
+ var networkStatus: NetworkReachabilityStatus = .reachable(.ethernetOrWiFi)
+
+ #if os(iOS)
+ if flags.contains(.isWWAN) { networkStatus = .reachable(.wwan) }
+ #endif
+
+ return networkStatus
+ }
+
+ func isNetworkReachable(with flags: SCNetworkReachabilityFlags) -> Bool {
+ let isReachable = flags.contains(.reachable)
+ let needsConnection = flags.contains(.connectionRequired)
+ let canConnectAutomatically = flags.contains(.connectionOnDemand) || flags.contains(.connectionOnTraffic)
+ let canConnectWithoutUserInteraction = canConnectAutomatically && !flags.contains(.interventionRequired)
+
+ return isReachable && (!needsConnection || canConnectWithoutUserInteraction)
+ }
+}
+
+// MARK: -
+
+extension NetworkReachabilityManager.NetworkReachabilityStatus: Equatable {}
+
+/// Returns whether the two network reachability status values are equal.
+///
+/// - parameter lhs: The left-hand side value to compare.
+/// - parameter rhs: The right-hand side value to compare.
+///
+/// - returns: `true` if the two values are equal, `false` otherwise.
+public func ==(
+ lhs: NetworkReachabilityManager.NetworkReachabilityStatus,
+ rhs: NetworkReachabilityManager.NetworkReachabilityStatus)
+ -> Bool
+{
+ switch (lhs, rhs) {
+ case (.unknown, .unknown):
+ return true
+ case (.notReachable, .notReachable):
+ return true
+ case let (.reachable(lhsConnectionType), .reachable(rhsConnectionType)):
+ return lhsConnectionType == rhsConnectionType
+ default:
+ return false
+ }
+}
+
+#endif
diff --git a/Pods/Alamofire/Source/Notifications.swift b/Pods/Alamofire/Source/Notifications.swift
new file mode 100644
index 0000000..e1ac31b
--- /dev/null
+++ b/Pods/Alamofire/Source/Notifications.swift
@@ -0,0 +1,55 @@
+//
+// Notifications.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+extension Notification.Name {
+ /// Used as a namespace for all `URLSessionTask` related notifications.
+ public struct Task {
+ /// Posted when a `URLSessionTask` is resumed. The notification `object` contains the resumed `URLSessionTask`.
+ public static let DidResume = Notification.Name(rawValue: "org.alamofire.notification.name.task.didResume")
+
+ /// Posted when a `URLSessionTask` is suspended. The notification `object` contains the suspended `URLSessionTask`.
+ public static let DidSuspend = Notification.Name(rawValue: "org.alamofire.notification.name.task.didSuspend")
+
+ /// Posted when a `URLSessionTask` is cancelled. The notification `object` contains the cancelled `URLSessionTask`.
+ public static let DidCancel = Notification.Name(rawValue: "org.alamofire.notification.name.task.didCancel")
+
+ /// Posted when a `URLSessionTask` is completed. The notification `object` contains the completed `URLSessionTask`.
+ public static let DidComplete = Notification.Name(rawValue: "org.alamofire.notification.name.task.didComplete")
+ }
+}
+
+// MARK: -
+
+extension Notification {
+ /// Used as a namespace for all `Notification` user info dictionary keys.
+ public struct Key {
+ /// User info dictionary key representing the `URLSessionTask` associated with the notification.
+ public static let Task = "org.alamofire.notification.key.task"
+
+ /// User info dictionary key representing the responseData associated with the notification.
+ public static let ResponseData = "org.alamofire.notification.key.responseData"
+ }
+}
diff --git a/Pods/Alamofire/Source/ParameterEncoding.swift b/Pods/Alamofire/Source/ParameterEncoding.swift
new file mode 100644
index 0000000..6195809
--- /dev/null
+++ b/Pods/Alamofire/Source/ParameterEncoding.swift
@@ -0,0 +1,483 @@
+//
+// ParameterEncoding.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// HTTP method definitions.
+///
+/// See https://tools.ietf.org/html/rfc7231#section-4.3
+public enum HTTPMethod: String {
+ case options = "OPTIONS"
+ case get = "GET"
+ case head = "HEAD"
+ case post = "POST"
+ case put = "PUT"
+ case patch = "PATCH"
+ case delete = "DELETE"
+ case trace = "TRACE"
+ case connect = "CONNECT"
+}
+
+// MARK: -
+
+/// A dictionary of parameters to apply to a `URLRequest`.
+public typealias Parameters = [String: Any]
+
+/// A type used to define how a set of parameters are applied to a `URLRequest`.
+public protocol ParameterEncoding {
+ /// Creates a URL request by encoding parameters and applying them onto an existing request.
+ ///
+ /// - parameter urlRequest: The request to have parameters applied.
+ /// - parameter parameters: The parameters to apply.
+ ///
+ /// - throws: An `AFError.parameterEncodingFailed` error if encoding fails.
+ ///
+ /// - returns: The encoded request.
+ func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest
+}
+
+// MARK: -
+
+/// Creates a url-encoded query string to be set as or appended to any existing URL query string or set as the HTTP
+/// body of the URL request. Whether the query string is set or appended to any existing URL query string or set as
+/// the HTTP body depends on the destination of the encoding.
+///
+/// The `Content-Type` HTTP header field of an encoded request with HTTP body is set to
+/// `application/x-www-form-urlencoded; charset=utf-8`.
+///
+/// There is no published specification for how to encode collection types. By default the convention of appending
+/// `[]` to the key for array values (`foo[]=1&foo[]=2`), and appending the key surrounded by square brackets for
+/// nested dictionary values (`foo[bar]=baz`) is used. Optionally, `ArrayEncoding` can be used to omit the
+/// square brackets appended to array keys.
+///
+/// `BoolEncoding` can be used to configure how boolean values are encoded. The default behavior is to encode
+/// `true` as 1 and `false` as 0.
+public struct URLEncoding: ParameterEncoding {
+
+ // MARK: Helper Types
+
+ /// Defines whether the url-encoded query string is applied to the existing query string or HTTP body of the
+ /// resulting URL request.
+ ///
+ /// - methodDependent: Applies encoded query string result to existing query string for `GET`, `HEAD` and `DELETE`
+ /// requests and sets as the HTTP body for requests with any other HTTP method.
+ /// - queryString: Sets or appends encoded query string result to existing query string.
+ /// - httpBody: Sets encoded query string result as the HTTP body of the URL request.
+ public enum Destination {
+ case methodDependent, queryString, httpBody
+ }
+
+ /// Configures how `Array` parameters are encoded.
+ ///
+ /// - brackets: An empty set of square brackets is appended to the key for every value.
+ /// This is the default behavior.
+ /// - noBrackets: No brackets are appended. The key is encoded as is.
+ public enum ArrayEncoding {
+ case brackets, noBrackets
+
+ func encode(key: String) -> String {
+ switch self {
+ case .brackets:
+ return "\(key)[]"
+ case .noBrackets:
+ return key
+ }
+ }
+ }
+
+ /// Configures how `Bool` parameters are encoded.
+ ///
+ /// - numeric: Encode `true` as `1` and `false` as `0`. This is the default behavior.
+ /// - literal: Encode `true` and `false` as string literals.
+ public enum BoolEncoding {
+ case numeric, literal
+
+ func encode(value: Bool) -> String {
+ switch self {
+ case .numeric:
+ return value ? "1" : "0"
+ case .literal:
+ return value ? "true" : "false"
+ }
+ }
+ }
+
+ // MARK: Properties
+
+ /// Returns a default `URLEncoding` instance.
+ public static var `default`: URLEncoding { return URLEncoding() }
+
+ /// Returns a `URLEncoding` instance with a `.methodDependent` destination.
+ public static var methodDependent: URLEncoding { return URLEncoding() }
+
+ /// Returns a `URLEncoding` instance with a `.queryString` destination.
+ public static var queryString: URLEncoding { return URLEncoding(destination: .queryString) }
+
+ /// Returns a `URLEncoding` instance with an `.httpBody` destination.
+ public static var httpBody: URLEncoding { return URLEncoding(destination: .httpBody) }
+
+ /// The destination defining where the encoded query string is to be applied to the URL request.
+ public let destination: Destination
+
+ /// The encoding to use for `Array` parameters.
+ public let arrayEncoding: ArrayEncoding
+
+ /// The encoding to use for `Bool` parameters.
+ public let boolEncoding: BoolEncoding
+
+ // MARK: Initialization
+
+ /// Creates a `URLEncoding` instance using the specified destination.
+ ///
+ /// - parameter destination: The destination defining where the encoded query string is to be applied.
+ /// - parameter arrayEncoding: The encoding to use for `Array` parameters.
+ /// - parameter boolEncoding: The encoding to use for `Bool` parameters.
+ ///
+ /// - returns: The new `URLEncoding` instance.
+ public init(destination: Destination = .methodDependent, arrayEncoding: ArrayEncoding = .brackets, boolEncoding: BoolEncoding = .numeric) {
+ self.destination = destination
+ self.arrayEncoding = arrayEncoding
+ self.boolEncoding = boolEncoding
+ }
+
+ // MARK: Encoding
+
+ /// Creates a URL request by encoding parameters and applying them onto an existing request.
+ ///
+ /// - parameter urlRequest: The request to have parameters applied.
+ /// - parameter parameters: The parameters to apply.
+ ///
+ /// - throws: An `Error` if the encoding process encounters an error.
+ ///
+ /// - returns: The encoded request.
+ public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
+ var urlRequest = try urlRequest.asURLRequest()
+
+ guard let parameters = parameters else { return urlRequest }
+
+ if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) {
+ guard let url = urlRequest.url else {
+ throw AFError.parameterEncodingFailed(reason: .missingURL)
+ }
+
+ if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty {
+ let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters)
+ urlComponents.percentEncodedQuery = percentEncodedQuery
+ urlRequest.url = urlComponents.url
+ }
+ } else {
+ if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
+ urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
+ }
+
+ urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)
+ }
+
+ return urlRequest
+ }
+
+ /// Creates percent-escaped, URL encoded query string components from the given key-value pair using recursion.
+ ///
+ /// - parameter key: The key of the query component.
+ /// - parameter value: The value of the query component.
+ ///
+ /// - returns: The percent-escaped, URL encoded query string components.
+ public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] {
+ var components: [(String, String)] = []
+
+ if let dictionary = value as? [String: Any] {
+ for (nestedKey, value) in dictionary {
+ components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value)
+ }
+ } else if let array = value as? [Any] {
+ for value in array {
+ components += queryComponents(fromKey: arrayEncoding.encode(key: key), value: value)
+ }
+ } else if let value = value as? NSNumber {
+ if value.isBool {
+ components.append((escape(key), escape(boolEncoding.encode(value: value.boolValue))))
+ } else {
+ components.append((escape(key), escape("\(value)")))
+ }
+ } else if let bool = value as? Bool {
+ components.append((escape(key), escape(boolEncoding.encode(value: bool))))
+ } else {
+ components.append((escape(key), escape("\(value)")))
+ }
+
+ return components
+ }
+
+ /// Returns a percent-escaped string following RFC 3986 for a query string key or value.
+ ///
+ /// RFC 3986 states that the following characters are "reserved" characters.
+ ///
+ /// - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
+ /// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
+ ///
+ /// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
+ /// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
+ /// should be percent-escaped in the query string.
+ ///
+ /// - parameter string: The string to be percent-escaped.
+ ///
+ /// - returns: The percent-escaped string.
+ public func escape(_ string: String) -> String {
+ let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
+ let subDelimitersToEncode = "!$&'()*+,;="
+
+ var allowedCharacterSet = CharacterSet.urlQueryAllowed
+ allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
+
+ var escaped = ""
+
+ //==========================================================================================================
+ //
+ // Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few
+ // hundred Chinese characters causes various malloc error crashes. To avoid this issue until iOS 8 is no
+ // longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead. For more
+ // info, please refer to:
+ //
+ // - https://github.com/Alamofire/Alamofire/issues/206
+ //
+ //==========================================================================================================
+
+ if #available(iOS 8.3, *) {
+ escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string
+ } else {
+ let batchSize = 50
+ var index = string.startIndex
+
+ while index != string.endIndex {
+ let startIndex = index
+ let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex
+ let range = startIndex.. String {
+ var components: [(String, String)] = []
+
+ for key in parameters.keys.sorted(by: <) {
+ let value = parameters[key]!
+ components += queryComponents(fromKey: key, value: value)
+ }
+ return components.map { "\($0)=\($1)" }.joined(separator: "&")
+ }
+
+ private func encodesParametersInURL(with method: HTTPMethod) -> Bool {
+ switch destination {
+ case .queryString:
+ return true
+ case .httpBody:
+ return false
+ default:
+ break
+ }
+
+ switch method {
+ case .get, .head, .delete:
+ return true
+ default:
+ return false
+ }
+ }
+}
+
+// MARK: -
+
+/// Uses `JSONSerialization` to create a JSON representation of the parameters object, which is set as the body of the
+/// request. The `Content-Type` HTTP header field of an encoded request is set to `application/json`.
+public struct JSONEncoding: ParameterEncoding {
+
+ // MARK: Properties
+
+ /// Returns a `JSONEncoding` instance with default writing options.
+ public static var `default`: JSONEncoding { return JSONEncoding() }
+
+ /// Returns a `JSONEncoding` instance with `.prettyPrinted` writing options.
+ public static var prettyPrinted: JSONEncoding { return JSONEncoding(options: .prettyPrinted) }
+
+ /// The options for writing the parameters as JSON data.
+ public let options: JSONSerialization.WritingOptions
+
+ // MARK: Initialization
+
+ /// Creates a `JSONEncoding` instance using the specified options.
+ ///
+ /// - parameter options: The options for writing the parameters as JSON data.
+ ///
+ /// - returns: The new `JSONEncoding` instance.
+ public init(options: JSONSerialization.WritingOptions = []) {
+ self.options = options
+ }
+
+ // MARK: Encoding
+
+ /// Creates a URL request by encoding parameters and applying them onto an existing request.
+ ///
+ /// - parameter urlRequest: The request to have parameters applied.
+ /// - parameter parameters: The parameters to apply.
+ ///
+ /// - throws: An `Error` if the encoding process encounters an error.
+ ///
+ /// - returns: The encoded request.
+ public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
+ var urlRequest = try urlRequest.asURLRequest()
+
+ guard let parameters = parameters else { return urlRequest }
+
+ do {
+ let data = try JSONSerialization.data(withJSONObject: parameters, options: options)
+
+ if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
+ urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+ }
+
+ urlRequest.httpBody = data
+ } catch {
+ throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
+ }
+
+ return urlRequest
+ }
+
+ /// Creates a URL request by encoding the JSON object and setting the resulting data on the HTTP body.
+ ///
+ /// - parameter urlRequest: The request to apply the JSON object to.
+ /// - parameter jsonObject: The JSON object to apply to the request.
+ ///
+ /// - throws: An `Error` if the encoding process encounters an error.
+ ///
+ /// - returns: The encoded request.
+ public func encode(_ urlRequest: URLRequestConvertible, withJSONObject jsonObject: Any? = nil) throws -> URLRequest {
+ var urlRequest = try urlRequest.asURLRequest()
+
+ guard let jsonObject = jsonObject else { return urlRequest }
+
+ do {
+ let data = try JSONSerialization.data(withJSONObject: jsonObject, options: options)
+
+ if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
+ urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
+ }
+
+ urlRequest.httpBody = data
+ } catch {
+ throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error))
+ }
+
+ return urlRequest
+ }
+}
+
+// MARK: -
+
+/// Uses `PropertyListSerialization` to create a plist representation of the parameters object, according to the
+/// associated format and write options values, which is set as the body of the request. The `Content-Type` HTTP header
+/// field of an encoded request is set to `application/x-plist`.
+public struct PropertyListEncoding: ParameterEncoding {
+
+ // MARK: Properties
+
+ /// Returns a default `PropertyListEncoding` instance.
+ public static var `default`: PropertyListEncoding { return PropertyListEncoding() }
+
+ /// Returns a `PropertyListEncoding` instance with xml formatting and default writing options.
+ public static var xml: PropertyListEncoding { return PropertyListEncoding(format: .xml) }
+
+ /// Returns a `PropertyListEncoding` instance with binary formatting and default writing options.
+ public static var binary: PropertyListEncoding { return PropertyListEncoding(format: .binary) }
+
+ /// The property list serialization format.
+ public let format: PropertyListSerialization.PropertyListFormat
+
+ /// The options for writing the parameters as plist data.
+ public let options: PropertyListSerialization.WriteOptions
+
+ // MARK: Initialization
+
+ /// Creates a `PropertyListEncoding` instance using the specified format and options.
+ ///
+ /// - parameter format: The property list serialization format.
+ /// - parameter options: The options for writing the parameters as plist data.
+ ///
+ /// - returns: The new `PropertyListEncoding` instance.
+ public init(
+ format: PropertyListSerialization.PropertyListFormat = .xml,
+ options: PropertyListSerialization.WriteOptions = 0)
+ {
+ self.format = format
+ self.options = options
+ }
+
+ // MARK: Encoding
+
+ /// Creates a URL request by encoding parameters and applying them onto an existing request.
+ ///
+ /// - parameter urlRequest: The request to have parameters applied.
+ /// - parameter parameters: The parameters to apply.
+ ///
+ /// - throws: An `Error` if the encoding process encounters an error.
+ ///
+ /// - returns: The encoded request.
+ public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
+ var urlRequest = try urlRequest.asURLRequest()
+
+ guard let parameters = parameters else { return urlRequest }
+
+ do {
+ let data = try PropertyListSerialization.data(
+ fromPropertyList: parameters,
+ format: format,
+ options: options
+ )
+
+ if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
+ urlRequest.setValue("application/x-plist", forHTTPHeaderField: "Content-Type")
+ }
+
+ urlRequest.httpBody = data
+ } catch {
+ throw AFError.parameterEncodingFailed(reason: .propertyListEncodingFailed(error: error))
+ }
+
+ return urlRequest
+ }
+}
+
+// MARK: -
+
+extension NSNumber {
+ fileprivate var isBool: Bool { return CFBooleanGetTypeID() == CFGetTypeID(self) }
+}
diff --git a/Pods/Alamofire/Source/Request.swift b/Pods/Alamofire/Source/Request.swift
new file mode 100644
index 0000000..2be2ce0
--- /dev/null
+++ b/Pods/Alamofire/Source/Request.swift
@@ -0,0 +1,660 @@
+//
+// Request.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// A type that can inspect and optionally adapt a `URLRequest` in some manner if necessary.
+public protocol RequestAdapter {
+ /// Inspects and adapts the specified `URLRequest` in some manner if necessary and returns the result.
+ ///
+ /// - parameter urlRequest: The URL request to adapt.
+ ///
+ /// - throws: An `Error` if the adaptation encounters an error.
+ ///
+ /// - returns: The adapted `URLRequest`.
+ func adapt(_ urlRequest: URLRequest) throws -> URLRequest
+}
+
+// MARK: -
+
+/// A closure executed when the `RequestRetrier` determines whether a `Request` should be retried or not.
+public typealias RequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval) -> Void
+
+/// A type that determines whether a request should be retried after being executed by the specified session manager
+/// and encountering an error.
+public protocol RequestRetrier {
+ /// Determines whether the `Request` should be retried by calling the `completion` closure.
+ ///
+ /// This operation is fully asynchronous. Any amount of time can be taken to determine whether the request needs
+ /// to be retried. The one requirement is that the completion closure is called to ensure the request is properly
+ /// cleaned up after.
+ ///
+ /// - parameter manager: The session manager the request was executed on.
+ /// - parameter request: The request that failed due to the encountered error.
+ /// - parameter error: The error encountered when executing the request.
+ /// - parameter completion: The completion closure to be executed when retry decision has been determined.
+ func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion)
+}
+
+// MARK: -
+
+protocol TaskConvertible {
+ func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask
+}
+
+/// A dictionary of headers to apply to a `URLRequest`.
+public typealias HTTPHeaders = [String: String]
+
+// MARK: -
+
+/// Responsible for sending a request and receiving the response and associated data from the server, as well as
+/// managing its underlying `URLSessionTask`.
+open class Request {
+
+ // MARK: Helper Types
+
+ /// A closure executed when monitoring upload or download progress of a request.
+ public typealias ProgressHandler = (Progress) -> Void
+
+ enum RequestTask {
+ case data(TaskConvertible?, URLSessionTask?)
+ case download(TaskConvertible?, URLSessionTask?)
+ case upload(TaskConvertible?, URLSessionTask?)
+ case stream(TaskConvertible?, URLSessionTask?)
+ }
+
+ // MARK: Properties
+
+ /// The delegate for the underlying task.
+ open internal(set) var delegate: TaskDelegate {
+ get {
+ taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }
+ return taskDelegate
+ }
+ set {
+ taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() }
+ taskDelegate = newValue
+ }
+ }
+
+ /// The underlying task.
+ open var task: URLSessionTask? { return delegate.task }
+
+ /// The session belonging to the underlying task.
+ public let session: URLSession
+
+ /// The request sent or to be sent to the server.
+ open var request: URLRequest? { return task?.originalRequest }
+
+ /// The response received from the server, if any.
+ open var response: HTTPURLResponse? { return task?.response as? HTTPURLResponse }
+
+ /// The number of times the request has been retried.
+ open internal(set) var retryCount: UInt = 0
+
+ let originalTask: TaskConvertible?
+
+ var startTime: CFAbsoluteTime?
+ var endTime: CFAbsoluteTime?
+
+ var validations: [() -> Void] = []
+
+ private var taskDelegate: TaskDelegate
+ private var taskDelegateLock = NSLock()
+
+ // MARK: Lifecycle
+
+ init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {
+ self.session = session
+
+ switch requestTask {
+ case .data(let originalTask, let task):
+ taskDelegate = DataTaskDelegate(task: task)
+ self.originalTask = originalTask
+ case .download(let originalTask, let task):
+ taskDelegate = DownloadTaskDelegate(task: task)
+ self.originalTask = originalTask
+ case .upload(let originalTask, let task):
+ taskDelegate = UploadTaskDelegate(task: task)
+ self.originalTask = originalTask
+ case .stream(let originalTask, let task):
+ taskDelegate = TaskDelegate(task: task)
+ self.originalTask = originalTask
+ }
+
+ delegate.error = error
+ delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }
+ }
+
+ // MARK: Authentication
+
+ /// Associates an HTTP Basic credential with the request.
+ ///
+ /// - parameter user: The user.
+ /// - parameter password: The password.
+ /// - parameter persistence: The URL credential persistence. `.ForSession` by default.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ open func authenticate(
+ user: String,
+ password: String,
+ persistence: URLCredential.Persistence = .forSession)
+ -> Self
+ {
+ let credential = URLCredential(user: user, password: password, persistence: persistence)
+ return authenticate(usingCredential: credential)
+ }
+
+ /// Associates a specified credential with the request.
+ ///
+ /// - parameter credential: The credential.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ open func authenticate(usingCredential credential: URLCredential) -> Self {
+ delegate.credential = credential
+ return self
+ }
+
+ /// Returns a base64 encoded basic authentication credential as an authorization header tuple.
+ ///
+ /// - parameter user: The user.
+ /// - parameter password: The password.
+ ///
+ /// - returns: A tuple with Authorization header and credential value if encoding succeeds, `nil` otherwise.
+ open class func authorizationHeader(user: String, password: String) -> (key: String, value: String)? {
+ guard let data = "\(user):\(password)".data(using: .utf8) else { return nil }
+
+ let credential = data.base64EncodedString(options: [])
+
+ return (key: "Authorization", value: "Basic \(credential)")
+ }
+
+ // MARK: State
+
+ /// Resumes the request.
+ open func resume() {
+ guard let task = task else { delegate.queue.isSuspended = false ; return }
+
+ if startTime == nil { startTime = CFAbsoluteTimeGetCurrent() }
+
+ task.resume()
+
+ NotificationCenter.default.post(
+ name: Notification.Name.Task.DidResume,
+ object: self,
+ userInfo: [Notification.Key.Task: task]
+ )
+ }
+
+ /// Suspends the request.
+ open func suspend() {
+ guard let task = task else { return }
+
+ task.suspend()
+
+ NotificationCenter.default.post(
+ name: Notification.Name.Task.DidSuspend,
+ object: self,
+ userInfo: [Notification.Key.Task: task]
+ )
+ }
+
+ /// Cancels the request.
+ open func cancel() {
+ guard let task = task else { return }
+
+ task.cancel()
+
+ NotificationCenter.default.post(
+ name: Notification.Name.Task.DidCancel,
+ object: self,
+ userInfo: [Notification.Key.Task: task]
+ )
+ }
+}
+
+// MARK: - CustomStringConvertible
+
+extension Request: CustomStringConvertible {
+ /// The textual representation used when written to an output stream, which includes the HTTP method and URL, as
+ /// well as the response status code if a response has been received.
+ open var description: String {
+ var components: [String] = []
+
+ if let HTTPMethod = request?.httpMethod {
+ components.append(HTTPMethod)
+ }
+
+ if let urlString = request?.url?.absoluteString {
+ components.append(urlString)
+ }
+
+ if let response = response {
+ components.append("(\(response.statusCode))")
+ }
+
+ return components.joined(separator: " ")
+ }
+}
+
+// MARK: - CustomDebugStringConvertible
+
+extension Request: CustomDebugStringConvertible {
+ /// The textual representation used when written to an output stream, in the form of a cURL command.
+ open var debugDescription: String {
+ return cURLRepresentation()
+ }
+
+ func cURLRepresentation() -> String {
+ var components = ["$ curl -v"]
+
+ guard let request = self.request,
+ let url = request.url,
+ let host = url.host
+ else {
+ return "$ curl command could not be created"
+ }
+
+ if let httpMethod = request.httpMethod, httpMethod != "GET" {
+ components.append("-X \(httpMethod)")
+ }
+
+ if let credentialStorage = self.session.configuration.urlCredentialStorage {
+ let protectionSpace = URLProtectionSpace(
+ host: host,
+ port: url.port ?? 0,
+ protocol: url.scheme,
+ realm: host,
+ authenticationMethod: NSURLAuthenticationMethodHTTPBasic
+ )
+
+ if let credentials = credentialStorage.credentials(for: protectionSpace)?.values {
+ for credential in credentials {
+ guard let user = credential.user, let password = credential.password else { continue }
+ components.append("-u \(user):\(password)")
+ }
+ } else {
+ if let credential = delegate.credential, let user = credential.user, let password = credential.password {
+ components.append("-u \(user):\(password)")
+ }
+ }
+ }
+
+ if session.configuration.httpShouldSetCookies {
+ if
+ let cookieStorage = session.configuration.httpCookieStorage,
+ let cookies = cookieStorage.cookies(for: url), !cookies.isEmpty
+ {
+ let string = cookies.reduce("") { $0 + "\($1.name)=\($1.value);" }
+
+ #if swift(>=3.2)
+ components.append("-b \"\(string[.. URLSessionTask {
+ do {
+ let urlRequest = try self.urlRequest.adapt(using: adapter)
+ return queue.sync { session.dataTask(with: urlRequest) }
+ } catch {
+ throw AdaptError(error: error)
+ }
+ }
+ }
+
+ // MARK: Properties
+
+ /// The request sent or to be sent to the server.
+ open override var request: URLRequest? {
+ if let request = super.request { return request }
+ if let requestable = originalTask as? Requestable { return requestable.urlRequest }
+
+ return nil
+ }
+
+ /// The progress of fetching the response data from the server for the request.
+ open var progress: Progress { return dataDelegate.progress }
+
+ var dataDelegate: DataTaskDelegate { return delegate as! DataTaskDelegate }
+
+ // MARK: Stream
+
+ /// Sets a closure to be called periodically during the lifecycle of the request as data is read from the server.
+ ///
+ /// This closure returns the bytes most recently received from the server, not including data from previous calls.
+ /// If this closure is set, data will only be available within this closure, and will not be saved elsewhere. It is
+ /// also important to note that the server data in any `Response` object will be `nil`.
+ ///
+ /// - parameter closure: The code to be executed periodically during the lifecycle of the request.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ open func stream(closure: ((Data) -> Void)? = nil) -> Self {
+ dataDelegate.dataStream = closure
+ return self
+ }
+
+ // MARK: Progress
+
+ /// Sets a closure to be called periodically during the lifecycle of the `Request` as data is read from the server.
+ ///
+ /// - parameter queue: The dispatch queue to execute the closure on.
+ /// - parameter closure: The code to be executed periodically as data is read from the server.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ open func downloadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self {
+ dataDelegate.progressHandler = (closure, queue)
+ return self
+ }
+}
+
+// MARK: -
+
+/// Specific type of `Request` that manages an underlying `URLSessionDownloadTask`.
+open class DownloadRequest: Request {
+
+ // MARK: Helper Types
+
+ /// A collection of options to be executed prior to moving a downloaded file from the temporary URL to the
+ /// destination URL.
+ public struct DownloadOptions: OptionSet {
+ /// Returns the raw bitmask value of the option and satisfies the `RawRepresentable` protocol.
+ public let rawValue: UInt
+
+ /// A `DownloadOptions` flag that creates intermediate directories for the destination URL if specified.
+ public static let createIntermediateDirectories = DownloadOptions(rawValue: 1 << 0)
+
+ /// A `DownloadOptions` flag that removes a previous file from the destination URL if specified.
+ public static let removePreviousFile = DownloadOptions(rawValue: 1 << 1)
+
+ /// Creates a `DownloadFileDestinationOptions` instance with the specified raw value.
+ ///
+ /// - parameter rawValue: The raw bitmask value for the option.
+ ///
+ /// - returns: A new log level instance.
+ public init(rawValue: UInt) {
+ self.rawValue = rawValue
+ }
+ }
+
+ /// A closure executed once a download request has successfully completed in order to determine where to move the
+ /// temporary file written to during the download process. The closure takes two arguments: the temporary file URL
+ /// and the URL response, and returns a two arguments: the file URL where the temporary file should be moved and
+ /// the options defining how the file should be moved.
+ public typealias DownloadFileDestination = (
+ _ temporaryURL: URL,
+ _ response: HTTPURLResponse)
+ -> (destinationURL: URL, options: DownloadOptions)
+
+ enum Downloadable: TaskConvertible {
+ case request(URLRequest)
+ case resumeData(Data)
+
+ func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
+ do {
+ let task: URLSessionTask
+
+ switch self {
+ case let .request(urlRequest):
+ let urlRequest = try urlRequest.adapt(using: adapter)
+ task = queue.sync { session.downloadTask(with: urlRequest) }
+ case let .resumeData(resumeData):
+ task = queue.sync { session.downloadTask(withResumeData: resumeData) }
+ }
+
+ return task
+ } catch {
+ throw AdaptError(error: error)
+ }
+ }
+ }
+
+ // MARK: Properties
+
+ /// The request sent or to be sent to the server.
+ open override var request: URLRequest? {
+ if let request = super.request { return request }
+
+ if let downloadable = originalTask as? Downloadable, case let .request(urlRequest) = downloadable {
+ return urlRequest
+ }
+
+ return nil
+ }
+
+ /// The resume data of the underlying download task if available after a failure.
+ open var resumeData: Data? { return downloadDelegate.resumeData }
+
+ /// The progress of downloading the response data from the server for the request.
+ open var progress: Progress { return downloadDelegate.progress }
+
+ var downloadDelegate: DownloadTaskDelegate { return delegate as! DownloadTaskDelegate }
+
+ // MARK: State
+
+ /// Cancels the request.
+ override open func cancel() {
+ cancel(createResumeData: true)
+ }
+
+ /// Cancels the request.
+ ///
+ /// - parameter createResumeData: Determines whether resume data is created via the underlying download task or not.
+ open func cancel(createResumeData: Bool) {
+ if createResumeData {
+ downloadDelegate.downloadTask.cancel { self.downloadDelegate.resumeData = $0 }
+ } else {
+ downloadDelegate.downloadTask.cancel()
+ }
+
+ NotificationCenter.default.post(
+ name: Notification.Name.Task.DidCancel,
+ object: self,
+ userInfo: [Notification.Key.Task: task as Any]
+ )
+ }
+
+ // MARK: Progress
+
+ /// Sets a closure to be called periodically during the lifecycle of the `Request` as data is read from the server.
+ ///
+ /// - parameter queue: The dispatch queue to execute the closure on.
+ /// - parameter closure: The code to be executed periodically as data is read from the server.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ open func downloadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self {
+ downloadDelegate.progressHandler = (closure, queue)
+ return self
+ }
+
+ // MARK: Destination
+
+ /// Creates a download file destination closure which uses the default file manager to move the temporary file to a
+ /// file URL in the first available directory with the specified search path directory and search path domain mask.
+ ///
+ /// - parameter directory: The search path directory. `.DocumentDirectory` by default.
+ /// - parameter domain: The search path domain mask. `.UserDomainMask` by default.
+ ///
+ /// - returns: A download file destination closure.
+ open class func suggestedDownloadDestination(
+ for directory: FileManager.SearchPathDirectory = .documentDirectory,
+ in domain: FileManager.SearchPathDomainMask = .userDomainMask)
+ -> DownloadFileDestination
+ {
+ return { temporaryURL, response in
+ let directoryURLs = FileManager.default.urls(for: directory, in: domain)
+
+ if !directoryURLs.isEmpty {
+ return (directoryURLs[0].appendingPathComponent(response.suggestedFilename!), [])
+ }
+
+ return (temporaryURL, [])
+ }
+ }
+}
+
+// MARK: -
+
+/// Specific type of `Request` that manages an underlying `URLSessionUploadTask`.
+open class UploadRequest: DataRequest {
+
+ // MARK: Helper Types
+
+ enum Uploadable: TaskConvertible {
+ case data(Data, URLRequest)
+ case file(URL, URLRequest)
+ case stream(InputStream, URLRequest)
+
+ func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
+ do {
+ let task: URLSessionTask
+
+ switch self {
+ case let .data(data, urlRequest):
+ let urlRequest = try urlRequest.adapt(using: adapter)
+ task = queue.sync { session.uploadTask(with: urlRequest, from: data) }
+ case let .file(url, urlRequest):
+ let urlRequest = try urlRequest.adapt(using: adapter)
+ task = queue.sync { session.uploadTask(with: urlRequest, fromFile: url) }
+ case let .stream(_, urlRequest):
+ let urlRequest = try urlRequest.adapt(using: adapter)
+ task = queue.sync { session.uploadTask(withStreamedRequest: urlRequest) }
+ }
+
+ return task
+ } catch {
+ throw AdaptError(error: error)
+ }
+ }
+ }
+
+ // MARK: Properties
+
+ /// The request sent or to be sent to the server.
+ open override var request: URLRequest? {
+ if let request = super.request { return request }
+
+ guard let uploadable = originalTask as? Uploadable else { return nil }
+
+ switch uploadable {
+ case .data(_, let urlRequest), .file(_, let urlRequest), .stream(_, let urlRequest):
+ return urlRequest
+ }
+ }
+
+ /// The progress of uploading the payload to the server for the upload request.
+ open var uploadProgress: Progress { return uploadDelegate.uploadProgress }
+
+ var uploadDelegate: UploadTaskDelegate { return delegate as! UploadTaskDelegate }
+
+ // MARK: Upload Progress
+
+ /// Sets a closure to be called periodically during the lifecycle of the `UploadRequest` as data is sent to
+ /// the server.
+ ///
+ /// After the data is sent to the server, the `progress(queue:closure:)` APIs can be used to monitor the progress
+ /// of data being read from the server.
+ ///
+ /// - parameter queue: The dispatch queue to execute the closure on.
+ /// - parameter closure: The code to be executed periodically as data is sent to the server.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ open func uploadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self {
+ uploadDelegate.uploadProgressHandler = (closure, queue)
+ return self
+ }
+}
+
+// MARK: -
+
+#if !os(watchOS)
+
+/// Specific type of `Request` that manages an underlying `URLSessionStreamTask`.
+@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+open class StreamRequest: Request {
+ enum Streamable: TaskConvertible {
+ case stream(hostName: String, port: Int)
+ case netService(NetService)
+
+ func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
+ let task: URLSessionTask
+
+ switch self {
+ case let .stream(hostName, port):
+ task = queue.sync { session.streamTask(withHostName: hostName, port: port) }
+ case let .netService(netService):
+ task = queue.sync { session.streamTask(with: netService) }
+ }
+
+ return task
+ }
+ }
+}
+
+#endif
diff --git a/Pods/Alamofire/Source/Response.swift b/Pods/Alamofire/Source/Response.swift
new file mode 100644
index 0000000..747a471
--- /dev/null
+++ b/Pods/Alamofire/Source/Response.swift
@@ -0,0 +1,567 @@
+//
+// Response.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// Used to store all data associated with an non-serialized response of a data or upload request.
+public struct DefaultDataResponse {
+ /// The URL request sent to the server.
+ public let request: URLRequest?
+
+ /// The server's response to the URL request.
+ public let response: HTTPURLResponse?
+
+ /// The data returned by the server.
+ public let data: Data?
+
+ /// The error encountered while executing or validating the request.
+ public let error: Error?
+
+ /// The timeline of the complete lifecycle of the request.
+ public let timeline: Timeline
+
+ var _metrics: AnyObject?
+
+ /// Creates a `DefaultDataResponse` instance from the specified parameters.
+ ///
+ /// - Parameters:
+ /// - request: The URL request sent to the server.
+ /// - response: The server's response to the URL request.
+ /// - data: The data returned by the server.
+ /// - error: The error encountered while executing or validating the request.
+ /// - timeline: The timeline of the complete lifecycle of the request. `Timeline()` by default.
+ /// - metrics: The task metrics containing the request / response statistics. `nil` by default.
+ public init(
+ request: URLRequest?,
+ response: HTTPURLResponse?,
+ data: Data?,
+ error: Error?,
+ timeline: Timeline = Timeline(),
+ metrics: AnyObject? = nil)
+ {
+ self.request = request
+ self.response = response
+ self.data = data
+ self.error = error
+ self.timeline = timeline
+ }
+}
+
+// MARK: -
+
+/// Used to store all data associated with a serialized response of a data or upload request.
+public struct DataResponse {
+ /// The URL request sent to the server.
+ public let request: URLRequest?
+
+ /// The server's response to the URL request.
+ public let response: HTTPURLResponse?
+
+ /// The data returned by the server.
+ public let data: Data?
+
+ /// The result of response serialization.
+ public let result: Result
+
+ /// The timeline of the complete lifecycle of the request.
+ public let timeline: Timeline
+
+ /// Returns the associated value of the result if it is a success, `nil` otherwise.
+ public var value: Value? { return result.value }
+
+ /// Returns the associated error value if the result if it is a failure, `nil` otherwise.
+ public var error: Error? { return result.error }
+
+ var _metrics: AnyObject?
+
+ /// Creates a `DataResponse` instance with the specified parameters derived from response serialization.
+ ///
+ /// - parameter request: The URL request sent to the server.
+ /// - parameter response: The server's response to the URL request.
+ /// - parameter data: The data returned by the server.
+ /// - parameter result: The result of response serialization.
+ /// - parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`.
+ ///
+ /// - returns: The new `DataResponse` instance.
+ public init(
+ request: URLRequest?,
+ response: HTTPURLResponse?,
+ data: Data?,
+ result: Result,
+ timeline: Timeline = Timeline())
+ {
+ self.request = request
+ self.response = response
+ self.data = data
+ self.result = result
+ self.timeline = timeline
+ }
+}
+
+// MARK: -
+
+extension DataResponse: CustomStringConvertible, CustomDebugStringConvertible {
+ /// The textual representation used when written to an output stream, which includes whether the result was a
+ /// success or failure.
+ public var description: String {
+ return result.debugDescription
+ }
+
+ /// The debug textual representation used when written to an output stream, which includes the URL request, the URL
+ /// response, the server data, the response serialization result and the timeline.
+ public var debugDescription: String {
+ var output: [String] = []
+
+ output.append(request != nil ? "[Request]: \(request!.httpMethod ?? "GET") \(request!)" : "[Request]: nil")
+ output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil")
+ output.append("[Data]: \(data?.count ?? 0) bytes")
+ output.append("[Result]: \(result.debugDescription)")
+ output.append("[Timeline]: \(timeline.debugDescription)")
+
+ return output.joined(separator: "\n")
+ }
+}
+
+// MARK: -
+
+extension DataResponse {
+ /// Evaluates the specified closure when the result of this `DataResponse` is a success, passing the unwrapped
+ /// result value as a parameter.
+ ///
+ /// Use the `map` method with a closure that does not throw. For example:
+ ///
+ /// let possibleData: DataResponse = ...
+ /// let possibleInt = possibleData.map { $0.count }
+ ///
+ /// - parameter transform: A closure that takes the success value of the instance's result.
+ ///
+ /// - returns: A `DataResponse` whose result wraps the value returned by the given closure. If this instance's
+ /// result is a failure, returns a response wrapping the same failure.
+ public func map(_ transform: (Value) -> T) -> DataResponse {
+ var response = DataResponse(
+ request: request,
+ response: self.response,
+ data: data,
+ result: result.map(transform),
+ timeline: timeline
+ )
+
+ response._metrics = _metrics
+
+ return response
+ }
+
+ /// Evaluates the given closure when the result of this `DataResponse` is a success, passing the unwrapped result
+ /// value as a parameter.
+ ///
+ /// Use the `flatMap` method with a closure that may throw an error. For example:
+ ///
+ /// let possibleData: DataResponse = ...
+ /// let possibleObject = possibleData.flatMap {
+ /// try JSONSerialization.jsonObject(with: $0)
+ /// }
+ ///
+ /// - parameter transform: A closure that takes the success value of the instance's result.
+ ///
+ /// - returns: A success or failure `DataResponse` depending on the result of the given closure. If this instance's
+ /// result is a failure, returns the same failure.
+ public func flatMap(_ transform: (Value) throws -> T) -> DataResponse {
+ var response = DataResponse(
+ request: request,
+ response: self.response,
+ data: data,
+ result: result.flatMap(transform),
+ timeline: timeline
+ )
+
+ response._metrics = _metrics
+
+ return response
+ }
+
+ /// Evaluates the specified closure when the `DataResponse` is a failure, passing the unwrapped error as a parameter.
+ ///
+ /// Use the `mapError` function with a closure that does not throw. For example:
+ ///
+ /// let possibleData: DataResponse = ...
+ /// let withMyError = possibleData.mapError { MyError.error($0) }
+ ///
+ /// - Parameter transform: A closure that takes the error of the instance.
+ /// - Returns: A `DataResponse` instance containing the result of the transform.
+ public func mapError(_ transform: (Error) -> E) -> DataResponse {
+ var response = DataResponse(
+ request: request,
+ response: self.response,
+ data: data,
+ result: result.mapError(transform),
+ timeline: timeline
+ )
+
+ response._metrics = _metrics
+
+ return response
+ }
+
+ /// Evaluates the specified closure when the `DataResponse` is a failure, passing the unwrapped error as a parameter.
+ ///
+ /// Use the `flatMapError` function with a closure that may throw an error. For example:
+ ///
+ /// let possibleData: DataResponse = ...
+ /// let possibleObject = possibleData.flatMapError {
+ /// try someFailableFunction(taking: $0)
+ /// }
+ ///
+ /// - Parameter transform: A throwing closure that takes the error of the instance.
+ ///
+ /// - Returns: A `DataResponse` instance containing the result of the transform.
+ public func flatMapError(_ transform: (Error) throws -> E) -> DataResponse {
+ var response = DataResponse(
+ request: request,
+ response: self.response,
+ data: data,
+ result: result.flatMapError(transform),
+ timeline: timeline
+ )
+
+ response._metrics = _metrics
+
+ return response
+ }
+}
+
+// MARK: -
+
+/// Used to store all data associated with an non-serialized response of a download request.
+public struct DefaultDownloadResponse {
+ /// The URL request sent to the server.
+ public let request: URLRequest?
+
+ /// The server's response to the URL request.
+ public let response: HTTPURLResponse?
+
+ /// The temporary destination URL of the data returned from the server.
+ public let temporaryURL: URL?
+
+ /// The final destination URL of the data returned from the server if it was moved.
+ public let destinationURL: URL?
+
+ /// The resume data generated if the request was cancelled.
+ public let resumeData: Data?
+
+ /// The error encountered while executing or validating the request.
+ public let error: Error?
+
+ /// The timeline of the complete lifecycle of the request.
+ public let timeline: Timeline
+
+ var _metrics: AnyObject?
+
+ /// Creates a `DefaultDownloadResponse` instance from the specified parameters.
+ ///
+ /// - Parameters:
+ /// - request: The URL request sent to the server.
+ /// - response: The server's response to the URL request.
+ /// - temporaryURL: The temporary destination URL of the data returned from the server.
+ /// - destinationURL: The final destination URL of the data returned from the server if it was moved.
+ /// - resumeData: The resume data generated if the request was cancelled.
+ /// - error: The error encountered while executing or validating the request.
+ /// - timeline: The timeline of the complete lifecycle of the request. `Timeline()` by default.
+ /// - metrics: The task metrics containing the request / response statistics. `nil` by default.
+ public init(
+ request: URLRequest?,
+ response: HTTPURLResponse?,
+ temporaryURL: URL?,
+ destinationURL: URL?,
+ resumeData: Data?,
+ error: Error?,
+ timeline: Timeline = Timeline(),
+ metrics: AnyObject? = nil)
+ {
+ self.request = request
+ self.response = response
+ self.temporaryURL = temporaryURL
+ self.destinationURL = destinationURL
+ self.resumeData = resumeData
+ self.error = error
+ self.timeline = timeline
+ }
+}
+
+// MARK: -
+
+/// Used to store all data associated with a serialized response of a download request.
+public struct DownloadResponse {
+ /// The URL request sent to the server.
+ public let request: URLRequest?
+
+ /// The server's response to the URL request.
+ public let response: HTTPURLResponse?
+
+ /// The temporary destination URL of the data returned from the server.
+ public let temporaryURL: URL?
+
+ /// The final destination URL of the data returned from the server if it was moved.
+ public let destinationURL: URL?
+
+ /// The resume data generated if the request was cancelled.
+ public let resumeData: Data?
+
+ /// The result of response serialization.
+ public let result: Result
+
+ /// The timeline of the complete lifecycle of the request.
+ public let timeline: Timeline
+
+ /// Returns the associated value of the result if it is a success, `nil` otherwise.
+ public var value: Value? { return result.value }
+
+ /// Returns the associated error value if the result if it is a failure, `nil` otherwise.
+ public var error: Error? { return result.error }
+
+ var _metrics: AnyObject?
+
+ /// Creates a `DownloadResponse` instance with the specified parameters derived from response serialization.
+ ///
+ /// - parameter request: The URL request sent to the server.
+ /// - parameter response: The server's response to the URL request.
+ /// - parameter temporaryURL: The temporary destination URL of the data returned from the server.
+ /// - parameter destinationURL: The final destination URL of the data returned from the server if it was moved.
+ /// - parameter resumeData: The resume data generated if the request was cancelled.
+ /// - parameter result: The result of response serialization.
+ /// - parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`.
+ ///
+ /// - returns: The new `DownloadResponse` instance.
+ public init(
+ request: URLRequest?,
+ response: HTTPURLResponse?,
+ temporaryURL: URL?,
+ destinationURL: URL?,
+ resumeData: Data?,
+ result: Result,
+ timeline: Timeline = Timeline())
+ {
+ self.request = request
+ self.response = response
+ self.temporaryURL = temporaryURL
+ self.destinationURL = destinationURL
+ self.resumeData = resumeData
+ self.result = result
+ self.timeline = timeline
+ }
+}
+
+// MARK: -
+
+extension DownloadResponse: CustomStringConvertible, CustomDebugStringConvertible {
+ /// The textual representation used when written to an output stream, which includes whether the result was a
+ /// success or failure.
+ public var description: String {
+ return result.debugDescription
+ }
+
+ /// The debug textual representation used when written to an output stream, which includes the URL request, the URL
+ /// response, the temporary and destination URLs, the resume data, the response serialization result and the
+ /// timeline.
+ public var debugDescription: String {
+ var output: [String] = []
+
+ output.append(request != nil ? "[Request]: \(request!.httpMethod ?? "GET") \(request!)" : "[Request]: nil")
+ output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil")
+ output.append("[TemporaryURL]: \(temporaryURL?.path ?? "nil")")
+ output.append("[DestinationURL]: \(destinationURL?.path ?? "nil")")
+ output.append("[ResumeData]: \(resumeData?.count ?? 0) bytes")
+ output.append("[Result]: \(result.debugDescription)")
+ output.append("[Timeline]: \(timeline.debugDescription)")
+
+ return output.joined(separator: "\n")
+ }
+}
+
+// MARK: -
+
+extension DownloadResponse {
+ /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped
+ /// result value as a parameter.
+ ///
+ /// Use the `map` method with a closure that does not throw. For example:
+ ///
+ /// let possibleData: DownloadResponse = ...
+ /// let possibleInt = possibleData.map { $0.count }
+ ///
+ /// - parameter transform: A closure that takes the success value of the instance's result.
+ ///
+ /// - returns: A `DownloadResponse` whose result wraps the value returned by the given closure. If this instance's
+ /// result is a failure, returns a response wrapping the same failure.
+ public func map(_ transform: (Value) -> T) -> DownloadResponse {
+ var response = DownloadResponse(
+ request: request,
+ response: self.response,
+ temporaryURL: temporaryURL,
+ destinationURL: destinationURL,
+ resumeData: resumeData,
+ result: result.map(transform),
+ timeline: timeline
+ )
+
+ response._metrics = _metrics
+
+ return response
+ }
+
+ /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped
+ /// result value as a parameter.
+ ///
+ /// Use the `flatMap` method with a closure that may throw an error. For example:
+ ///
+ /// let possibleData: DownloadResponse = ...
+ /// let possibleObject = possibleData.flatMap {
+ /// try JSONSerialization.jsonObject(with: $0)
+ /// }
+ ///
+ /// - parameter transform: A closure that takes the success value of the instance's result.
+ ///
+ /// - returns: A success or failure `DownloadResponse` depending on the result of the given closure. If this
+ /// instance's result is a failure, returns the same failure.
+ public func flatMap(_ transform: (Value) throws -> T) -> DownloadResponse {
+ var response = DownloadResponse(
+ request: request,
+ response: self.response,
+ temporaryURL: temporaryURL,
+ destinationURL: destinationURL,
+ resumeData: resumeData,
+ result: result.flatMap(transform),
+ timeline: timeline
+ )
+
+ response._metrics = _metrics
+
+ return response
+ }
+
+ /// Evaluates the specified closure when the `DownloadResponse` is a failure, passing the unwrapped error as a parameter.
+ ///
+ /// Use the `mapError` function with a closure that does not throw. For example:
+ ///
+ /// let possibleData: DownloadResponse = ...
+ /// let withMyError = possibleData.mapError { MyError.error($0) }
+ ///
+ /// - Parameter transform: A closure that takes the error of the instance.
+ /// - Returns: A `DownloadResponse` instance containing the result of the transform.
+ public func mapError(_ transform: (Error) -> E) -> DownloadResponse {
+ var response = DownloadResponse(
+ request: request,
+ response: self.response,
+ temporaryURL: temporaryURL,
+ destinationURL: destinationURL,
+ resumeData: resumeData,
+ result: result.mapError(transform),
+ timeline: timeline
+ )
+
+ response._metrics = _metrics
+
+ return response
+ }
+
+ /// Evaluates the specified closure when the `DownloadResponse` is a failure, passing the unwrapped error as a parameter.
+ ///
+ /// Use the `flatMapError` function with a closure that may throw an error. For example:
+ ///
+ /// let possibleData: DownloadResponse = ...
+ /// let possibleObject = possibleData.flatMapError {
+ /// try someFailableFunction(taking: $0)
+ /// }
+ ///
+ /// - Parameter transform: A throwing closure that takes the error of the instance.
+ ///
+ /// - Returns: A `DownloadResponse` instance containing the result of the transform.
+ public func flatMapError(_ transform: (Error) throws -> E) -> DownloadResponse {
+ var response = DownloadResponse(
+ request: request,
+ response: self.response,
+ temporaryURL: temporaryURL,
+ destinationURL: destinationURL,
+ resumeData: resumeData,
+ result: result.flatMapError(transform),
+ timeline: timeline
+ )
+
+ response._metrics = _metrics
+
+ return response
+ }
+}
+
+// MARK: -
+
+protocol Response {
+ /// The task metrics containing the request / response statistics.
+ var _metrics: AnyObject? { get set }
+ mutating func add(_ metrics: AnyObject?)
+}
+
+extension Response {
+ mutating func add(_ metrics: AnyObject?) {
+ #if !os(watchOS)
+ guard #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) else { return }
+ guard let metrics = metrics as? URLSessionTaskMetrics else { return }
+
+ _metrics = metrics
+ #endif
+ }
+}
+
+// MARK: -
+
+@available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
+extension DefaultDataResponse: Response {
+#if !os(watchOS)
+ /// The task metrics containing the request / response statistics.
+ public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
+#endif
+}
+
+@available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
+extension DataResponse: Response {
+#if !os(watchOS)
+ /// The task metrics containing the request / response statistics.
+ public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
+#endif
+}
+
+@available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
+extension DefaultDownloadResponse: Response {
+#if !os(watchOS)
+ /// The task metrics containing the request / response statistics.
+ public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
+#endif
+}
+
+@available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
+extension DownloadResponse: Response {
+#if !os(watchOS)
+ /// The task metrics containing the request / response statistics.
+ public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics }
+#endif
+}
diff --git a/Pods/Alamofire/Source/ResponseSerialization.swift b/Pods/Alamofire/Source/ResponseSerialization.swift
new file mode 100644
index 0000000..9cc105a
--- /dev/null
+++ b/Pods/Alamofire/Source/ResponseSerialization.swift
@@ -0,0 +1,715 @@
+//
+// ResponseSerialization.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// The type in which all data response serializers must conform to in order to serialize a response.
+public protocol DataResponseSerializerProtocol {
+ /// The type of serialized object to be created by this `DataResponseSerializerType`.
+ associatedtype SerializedObject
+
+ /// A closure used by response handlers that takes a request, response, data and error and returns a result.
+ var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result { get }
+}
+
+// MARK: -
+
+/// A generic `DataResponseSerializerType` used to serialize a request, response, and data into a serialized object.
+public struct DataResponseSerializer: DataResponseSerializerProtocol {
+ /// The type of serialized object to be created by this `DataResponseSerializer`.
+ public typealias SerializedObject = Value
+
+ /// A closure used by response handlers that takes a request, response, data and error and returns a result.
+ public var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result
+
+ /// Initializes the `ResponseSerializer` instance with the given serialize response closure.
+ ///
+ /// - parameter serializeResponse: The closure used to serialize the response.
+ ///
+ /// - returns: The new generic response serializer instance.
+ public init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result) {
+ self.serializeResponse = serializeResponse
+ }
+}
+
+// MARK: -
+
+/// The type in which all download response serializers must conform to in order to serialize a response.
+public protocol DownloadResponseSerializerProtocol {
+ /// The type of serialized object to be created by this `DownloadResponseSerializerType`.
+ associatedtype SerializedObject
+
+ /// A closure used by response handlers that takes a request, response, url and error and returns a result.
+ var serializeResponse: (URLRequest?, HTTPURLResponse?, URL?, Error?) -> Result { get }
+}
+
+// MARK: -
+
+/// A generic `DownloadResponseSerializerType` used to serialize a request, response, and data into a serialized object.
+public struct DownloadResponseSerializer: DownloadResponseSerializerProtocol {
+ /// The type of serialized object to be created by this `DownloadResponseSerializer`.
+ public typealias SerializedObject = Value
+
+ /// A closure used by response handlers that takes a request, response, url and error and returns a result.
+ public var serializeResponse: (URLRequest?, HTTPURLResponse?, URL?, Error?) -> Result
+
+ /// Initializes the `ResponseSerializer` instance with the given serialize response closure.
+ ///
+ /// - parameter serializeResponse: The closure used to serialize the response.
+ ///
+ /// - returns: The new generic response serializer instance.
+ public init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, URL?, Error?) -> Result) {
+ self.serializeResponse = serializeResponse
+ }
+}
+
+// MARK: - Timeline
+
+extension Request {
+ var timeline: Timeline {
+ let requestStartTime = self.startTime ?? CFAbsoluteTimeGetCurrent()
+ let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent()
+ let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime
+
+ return Timeline(
+ requestStartTime: requestStartTime,
+ initialResponseTime: initialResponseTime,
+ requestCompletedTime: requestCompletedTime,
+ serializationCompletedTime: CFAbsoluteTimeGetCurrent()
+ )
+ }
+}
+
+// MARK: - Default
+
+extension DataRequest {
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter queue: The queue on which the completion handler is dispatched.
+ /// - parameter completionHandler: The code to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self {
+ delegate.queue.addOperation {
+ (queue ?? DispatchQueue.main).async {
+ var dataResponse = DefaultDataResponse(
+ request: self.request,
+ response: self.response,
+ data: self.delegate.data,
+ error: self.delegate.error,
+ timeline: self.timeline
+ )
+
+ dataResponse.add(self.delegate.metrics)
+
+ completionHandler(dataResponse)
+ }
+ }
+
+ return self
+ }
+
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter queue: The queue on which the completion handler is dispatched.
+ /// - parameter responseSerializer: The response serializer responsible for serializing the request, response,
+ /// and data.
+ /// - parameter completionHandler: The code to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func response(
+ queue: DispatchQueue? = nil,
+ responseSerializer: T,
+ completionHandler: @escaping (DataResponse) -> Void)
+ -> Self
+ {
+ delegate.queue.addOperation {
+ let result = responseSerializer.serializeResponse(
+ self.request,
+ self.response,
+ self.delegate.data,
+ self.delegate.error
+ )
+
+ var dataResponse = DataResponse(
+ request: self.request,
+ response: self.response,
+ data: self.delegate.data,
+ result: result,
+ timeline: self.timeline
+ )
+
+ dataResponse.add(self.delegate.metrics)
+
+ (queue ?? DispatchQueue.main).async { completionHandler(dataResponse) }
+ }
+
+ return self
+ }
+}
+
+extension DownloadRequest {
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter queue: The queue on which the completion handler is dispatched.
+ /// - parameter completionHandler: The code to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func response(
+ queue: DispatchQueue? = nil,
+ completionHandler: @escaping (DefaultDownloadResponse) -> Void)
+ -> Self
+ {
+ delegate.queue.addOperation {
+ (queue ?? DispatchQueue.main).async {
+ var downloadResponse = DefaultDownloadResponse(
+ request: self.request,
+ response: self.response,
+ temporaryURL: self.downloadDelegate.temporaryURL,
+ destinationURL: self.downloadDelegate.destinationURL,
+ resumeData: self.downloadDelegate.resumeData,
+ error: self.downloadDelegate.error,
+ timeline: self.timeline
+ )
+
+ downloadResponse.add(self.delegate.metrics)
+
+ completionHandler(downloadResponse)
+ }
+ }
+
+ return self
+ }
+
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter queue: The queue on which the completion handler is dispatched.
+ /// - parameter responseSerializer: The response serializer responsible for serializing the request, response,
+ /// and data contained in the destination url.
+ /// - parameter completionHandler: The code to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func response(
+ queue: DispatchQueue? = nil,
+ responseSerializer: T,
+ completionHandler: @escaping (DownloadResponse) -> Void)
+ -> Self
+ {
+ delegate.queue.addOperation {
+ let result = responseSerializer.serializeResponse(
+ self.request,
+ self.response,
+ self.downloadDelegate.fileURL,
+ self.downloadDelegate.error
+ )
+
+ var downloadResponse = DownloadResponse(
+ request: self.request,
+ response: self.response,
+ temporaryURL: self.downloadDelegate.temporaryURL,
+ destinationURL: self.downloadDelegate.destinationURL,
+ resumeData: self.downloadDelegate.resumeData,
+ result: result,
+ timeline: self.timeline
+ )
+
+ downloadResponse.add(self.delegate.metrics)
+
+ (queue ?? DispatchQueue.main).async { completionHandler(downloadResponse) }
+ }
+
+ return self
+ }
+}
+
+// MARK: - Data
+
+extension Request {
+ /// Returns a result data type that contains the response data as-is.
+ ///
+ /// - parameter response: The response from the server.
+ /// - parameter data: The data returned from the server.
+ /// - parameter error: The error already encountered if it exists.
+ ///
+ /// - returns: The result data type.
+ public static func serializeResponseData(response: HTTPURLResponse?, data: Data?, error: Error?) -> Result {
+ guard error == nil else { return .failure(error!) }
+
+ if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(Data()) }
+
+ guard let validData = data else {
+ return .failure(AFError.responseSerializationFailed(reason: .inputDataNil))
+ }
+
+ return .success(validData)
+ }
+}
+
+extension DataRequest {
+ /// Creates a response serializer that returns the associated data as-is.
+ ///
+ /// - returns: A data response serializer.
+ public static func dataResponseSerializer() -> DataResponseSerializer {
+ return DataResponseSerializer { _, response, data, error in
+ return Request.serializeResponseData(response: response, data: data, error: error)
+ }
+ }
+
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter completionHandler: The code to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func responseData(
+ queue: DispatchQueue? = nil,
+ completionHandler: @escaping (DataResponse) -> Void)
+ -> Self
+ {
+ return response(
+ queue: queue,
+ responseSerializer: DataRequest.dataResponseSerializer(),
+ completionHandler: completionHandler
+ )
+ }
+}
+
+extension DownloadRequest {
+ /// Creates a response serializer that returns the associated data as-is.
+ ///
+ /// - returns: A data response serializer.
+ public static func dataResponseSerializer() -> DownloadResponseSerializer {
+ return DownloadResponseSerializer { _, response, fileURL, error in
+ guard error == nil else { return .failure(error!) }
+
+ guard let fileURL = fileURL else {
+ return .failure(AFError.responseSerializationFailed(reason: .inputFileNil))
+ }
+
+ do {
+ let data = try Data(contentsOf: fileURL)
+ return Request.serializeResponseData(response: response, data: data, error: error)
+ } catch {
+ return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL)))
+ }
+ }
+ }
+
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter completionHandler: The code to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func responseData(
+ queue: DispatchQueue? = nil,
+ completionHandler: @escaping (DownloadResponse) -> Void)
+ -> Self
+ {
+ return response(
+ queue: queue,
+ responseSerializer: DownloadRequest.dataResponseSerializer(),
+ completionHandler: completionHandler
+ )
+ }
+}
+
+// MARK: - String
+
+extension Request {
+ /// Returns a result string type initialized from the response data with the specified string encoding.
+ ///
+ /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server
+ /// response, falling back to the default HTTP default character set, ISO-8859-1.
+ /// - parameter response: The response from the server.
+ /// - parameter data: The data returned from the server.
+ /// - parameter error: The error already encountered if it exists.
+ ///
+ /// - returns: The result data type.
+ public static func serializeResponseString(
+ encoding: String.Encoding?,
+ response: HTTPURLResponse?,
+ data: Data?,
+ error: Error?)
+ -> Result
+ {
+ guard error == nil else { return .failure(error!) }
+
+ if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success("") }
+
+ guard let validData = data else {
+ return .failure(AFError.responseSerializationFailed(reason: .inputDataNil))
+ }
+
+ var convertedEncoding = encoding
+
+ if let encodingName = response?.textEncodingName as CFString?, convertedEncoding == nil {
+ convertedEncoding = String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(
+ CFStringConvertIANACharSetNameToEncoding(encodingName))
+ )
+ }
+
+ let actualEncoding = convertedEncoding ?? .isoLatin1
+
+ if let string = String(data: validData, encoding: actualEncoding) {
+ return .success(string)
+ } else {
+ return .failure(AFError.responseSerializationFailed(reason: .stringSerializationFailed(encoding: actualEncoding)))
+ }
+ }
+}
+
+extension DataRequest {
+ /// Creates a response serializer that returns a result string type initialized from the response data with
+ /// the specified string encoding.
+ ///
+ /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server
+ /// response, falling back to the default HTTP default character set, ISO-8859-1.
+ ///
+ /// - returns: A string response serializer.
+ public static func stringResponseSerializer(encoding: String.Encoding? = nil) -> DataResponseSerializer {
+ return DataResponseSerializer { _, response, data, error in
+ return Request.serializeResponseString(encoding: encoding, response: response, data: data, error: error)
+ }
+ }
+
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the
+ /// server response, falling back to the default HTTP default character set,
+ /// ISO-8859-1.
+ /// - parameter completionHandler: A closure to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func responseString(
+ queue: DispatchQueue? = nil,
+ encoding: String.Encoding? = nil,
+ completionHandler: @escaping (DataResponse) -> Void)
+ -> Self
+ {
+ return response(
+ queue: queue,
+ responseSerializer: DataRequest.stringResponseSerializer(encoding: encoding),
+ completionHandler: completionHandler
+ )
+ }
+}
+
+extension DownloadRequest {
+ /// Creates a response serializer that returns a result string type initialized from the response data with
+ /// the specified string encoding.
+ ///
+ /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server
+ /// response, falling back to the default HTTP default character set, ISO-8859-1.
+ ///
+ /// - returns: A string response serializer.
+ public static func stringResponseSerializer(encoding: String.Encoding? = nil) -> DownloadResponseSerializer {
+ return DownloadResponseSerializer { _, response, fileURL, error in
+ guard error == nil else { return .failure(error!) }
+
+ guard let fileURL = fileURL else {
+ return .failure(AFError.responseSerializationFailed(reason: .inputFileNil))
+ }
+
+ do {
+ let data = try Data(contentsOf: fileURL)
+ return Request.serializeResponseString(encoding: encoding, response: response, data: data, error: error)
+ } catch {
+ return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL)))
+ }
+ }
+ }
+
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the
+ /// server response, falling back to the default HTTP default character set,
+ /// ISO-8859-1.
+ /// - parameter completionHandler: A closure to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func responseString(
+ queue: DispatchQueue? = nil,
+ encoding: String.Encoding? = nil,
+ completionHandler: @escaping (DownloadResponse) -> Void)
+ -> Self
+ {
+ return response(
+ queue: queue,
+ responseSerializer: DownloadRequest.stringResponseSerializer(encoding: encoding),
+ completionHandler: completionHandler
+ )
+ }
+}
+
+// MARK: - JSON
+
+extension Request {
+ /// Returns a JSON object contained in a result type constructed from the response data using `JSONSerialization`
+ /// with the specified reading options.
+ ///
+ /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
+ /// - parameter response: The response from the server.
+ /// - parameter data: The data returned from the server.
+ /// - parameter error: The error already encountered if it exists.
+ ///
+ /// - returns: The result data type.
+ public static func serializeResponseJSON(
+ options: JSONSerialization.ReadingOptions,
+ response: HTTPURLResponse?,
+ data: Data?,
+ error: Error?)
+ -> Result
+ {
+ guard error == nil else { return .failure(error!) }
+
+ if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(NSNull()) }
+
+ guard let validData = data, validData.count > 0 else {
+ return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength))
+ }
+
+ do {
+ let json = try JSONSerialization.jsonObject(with: validData, options: options)
+ return .success(json)
+ } catch {
+ return .failure(AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error)))
+ }
+ }
+}
+
+extension DataRequest {
+ /// Creates a response serializer that returns a JSON object result type constructed from the response data using
+ /// `JSONSerialization` with the specified reading options.
+ ///
+ /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
+ ///
+ /// - returns: A JSON object response serializer.
+ public static func jsonResponseSerializer(
+ options: JSONSerialization.ReadingOptions = .allowFragments)
+ -> DataResponseSerializer
+ {
+ return DataResponseSerializer { _, response, data, error in
+ return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
+ }
+ }
+
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
+ /// - parameter completionHandler: A closure to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func responseJSON(
+ queue: DispatchQueue? = nil,
+ options: JSONSerialization.ReadingOptions = .allowFragments,
+ completionHandler: @escaping (DataResponse) -> Void)
+ -> Self
+ {
+ return response(
+ queue: queue,
+ responseSerializer: DataRequest.jsonResponseSerializer(options: options),
+ completionHandler: completionHandler
+ )
+ }
+}
+
+extension DownloadRequest {
+ /// Creates a response serializer that returns a JSON object result type constructed from the response data using
+ /// `JSONSerialization` with the specified reading options.
+ ///
+ /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
+ ///
+ /// - returns: A JSON object response serializer.
+ public static func jsonResponseSerializer(
+ options: JSONSerialization.ReadingOptions = .allowFragments)
+ -> DownloadResponseSerializer
+ {
+ return DownloadResponseSerializer { _, response, fileURL, error in
+ guard error == nil else { return .failure(error!) }
+
+ guard let fileURL = fileURL else {
+ return .failure(AFError.responseSerializationFailed(reason: .inputFileNil))
+ }
+
+ do {
+ let data = try Data(contentsOf: fileURL)
+ return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
+ } catch {
+ return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL)))
+ }
+ }
+ }
+
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`.
+ /// - parameter completionHandler: A closure to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func responseJSON(
+ queue: DispatchQueue? = nil,
+ options: JSONSerialization.ReadingOptions = .allowFragments,
+ completionHandler: @escaping (DownloadResponse) -> Void)
+ -> Self
+ {
+ return response(
+ queue: queue,
+ responseSerializer: DownloadRequest.jsonResponseSerializer(options: options),
+ completionHandler: completionHandler
+ )
+ }
+}
+
+// MARK: - Property List
+
+extension Request {
+ /// Returns a plist object contained in a result type constructed from the response data using
+ /// `PropertyListSerialization` with the specified reading options.
+ ///
+ /// - parameter options: The property list reading options. Defaults to `[]`.
+ /// - parameter response: The response from the server.
+ /// - parameter data: The data returned from the server.
+ /// - parameter error: The error already encountered if it exists.
+ ///
+ /// - returns: The result data type.
+ public static func serializeResponsePropertyList(
+ options: PropertyListSerialization.ReadOptions,
+ response: HTTPURLResponse?,
+ data: Data?,
+ error: Error?)
+ -> Result
+ {
+ guard error == nil else { return .failure(error!) }
+
+ if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(NSNull()) }
+
+ guard let validData = data, validData.count > 0 else {
+ return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength))
+ }
+
+ do {
+ let plist = try PropertyListSerialization.propertyList(from: validData, options: options, format: nil)
+ return .success(plist)
+ } catch {
+ return .failure(AFError.responseSerializationFailed(reason: .propertyListSerializationFailed(error: error)))
+ }
+ }
+}
+
+extension DataRequest {
+ /// Creates a response serializer that returns an object constructed from the response data using
+ /// `PropertyListSerialization` with the specified reading options.
+ ///
+ /// - parameter options: The property list reading options. Defaults to `[]`.
+ ///
+ /// - returns: A property list object response serializer.
+ public static func propertyListResponseSerializer(
+ options: PropertyListSerialization.ReadOptions = [])
+ -> DataResponseSerializer
+ {
+ return DataResponseSerializer { _, response, data, error in
+ return Request.serializeResponsePropertyList(options: options, response: response, data: data, error: error)
+ }
+ }
+
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter options: The property list reading options. Defaults to `[]`.
+ /// - parameter completionHandler: A closure to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func responsePropertyList(
+ queue: DispatchQueue? = nil,
+ options: PropertyListSerialization.ReadOptions = [],
+ completionHandler: @escaping (DataResponse) -> Void)
+ -> Self
+ {
+ return response(
+ queue: queue,
+ responseSerializer: DataRequest.propertyListResponseSerializer(options: options),
+ completionHandler: completionHandler
+ )
+ }
+}
+
+extension DownloadRequest {
+ /// Creates a response serializer that returns an object constructed from the response data using
+ /// `PropertyListSerialization` with the specified reading options.
+ ///
+ /// - parameter options: The property list reading options. Defaults to `[]`.
+ ///
+ /// - returns: A property list object response serializer.
+ public static func propertyListResponseSerializer(
+ options: PropertyListSerialization.ReadOptions = [])
+ -> DownloadResponseSerializer
+ {
+ return DownloadResponseSerializer { _, response, fileURL, error in
+ guard error == nil else { return .failure(error!) }
+
+ guard let fileURL = fileURL else {
+ return .failure(AFError.responseSerializationFailed(reason: .inputFileNil))
+ }
+
+ do {
+ let data = try Data(contentsOf: fileURL)
+ return Request.serializeResponsePropertyList(options: options, response: response, data: data, error: error)
+ } catch {
+ return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL)))
+ }
+ }
+ }
+
+ /// Adds a handler to be called once the request has finished.
+ ///
+ /// - parameter options: The property list reading options. Defaults to `[]`.
+ /// - parameter completionHandler: A closure to be executed once the request has finished.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func responsePropertyList(
+ queue: DispatchQueue? = nil,
+ options: PropertyListSerialization.ReadOptions = [],
+ completionHandler: @escaping (DownloadResponse) -> Void)
+ -> Self
+ {
+ return response(
+ queue: queue,
+ responseSerializer: DownloadRequest.propertyListResponseSerializer(options: options),
+ completionHandler: completionHandler
+ )
+ }
+}
+
+/// A set of HTTP response status code that do not contain response data.
+private let emptyDataStatusCodes: Set = [204, 205]
diff --git a/Pods/Alamofire/Source/Result.swift b/Pods/Alamofire/Source/Result.swift
new file mode 100644
index 0000000..e092808
--- /dev/null
+++ b/Pods/Alamofire/Source/Result.swift
@@ -0,0 +1,300 @@
+//
+// Result.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// Used to represent whether a request was successful or encountered an error.
+///
+/// - success: The request and all post processing operations were successful resulting in the serialization of the
+/// provided associated value.
+///
+/// - failure: The request encountered an error resulting in a failure. The associated values are the original data
+/// provided by the server as well as the error that caused the failure.
+public enum Result {
+ case success(Value)
+ case failure(Error)
+
+ /// Returns `true` if the result is a success, `false` otherwise.
+ public var isSuccess: Bool {
+ switch self {
+ case .success:
+ return true
+ case .failure:
+ return false
+ }
+ }
+
+ /// Returns `true` if the result is a failure, `false` otherwise.
+ public var isFailure: Bool {
+ return !isSuccess
+ }
+
+ /// Returns the associated value if the result is a success, `nil` otherwise.
+ public var value: Value? {
+ switch self {
+ case .success(let value):
+ return value
+ case .failure:
+ return nil
+ }
+ }
+
+ /// Returns the associated error value if the result is a failure, `nil` otherwise.
+ public var error: Error? {
+ switch self {
+ case .success:
+ return nil
+ case .failure(let error):
+ return error
+ }
+ }
+}
+
+// MARK: - CustomStringConvertible
+
+extension Result: CustomStringConvertible {
+ /// The textual representation used when written to an output stream, which includes whether the result was a
+ /// success or failure.
+ public var description: String {
+ switch self {
+ case .success:
+ return "SUCCESS"
+ case .failure:
+ return "FAILURE"
+ }
+ }
+}
+
+// MARK: - CustomDebugStringConvertible
+
+extension Result: CustomDebugStringConvertible {
+ /// The debug textual representation used when written to an output stream, which includes whether the result was a
+ /// success or failure in addition to the value or error.
+ public var debugDescription: String {
+ switch self {
+ case .success(let value):
+ return "SUCCESS: \(value)"
+ case .failure(let error):
+ return "FAILURE: \(error)"
+ }
+ }
+}
+
+// MARK: - Functional APIs
+
+extension Result {
+ /// Creates a `Result` instance from the result of a closure.
+ ///
+ /// A failure result is created when the closure throws, and a success result is created when the closure
+ /// succeeds without throwing an error.
+ ///
+ /// func someString() throws -> String { ... }
+ ///
+ /// let result = Result(value: {
+ /// return try someString()
+ /// })
+ ///
+ /// // The type of result is Result
+ ///
+ /// The trailing closure syntax is also supported:
+ ///
+ /// let result = Result { try someString() }
+ ///
+ /// - parameter value: The closure to execute and create the result for.
+ public init(value: () throws -> Value) {
+ do {
+ self = try .success(value())
+ } catch {
+ self = .failure(error)
+ }
+ }
+
+ /// Returns the success value, or throws the failure error.
+ ///
+ /// let possibleString: Result = .success("success")
+ /// try print(possibleString.unwrap())
+ /// // Prints "success"
+ ///
+ /// let noString: Result = .failure(error)
+ /// try print(noString.unwrap())
+ /// // Throws error
+ public func unwrap() throws -> Value {
+ switch self {
+ case .success(let value):
+ return value
+ case .failure(let error):
+ throw error
+ }
+ }
+
+ /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter.
+ ///
+ /// Use the `map` method with a closure that does not throw. For example:
+ ///
+ /// let possibleData: Result = .success(Data())
+ /// let possibleInt = possibleData.map { $0.count }
+ /// try print(possibleInt.unwrap())
+ /// // Prints "0"
+ ///
+ /// let noData: Result = .failure(error)
+ /// let noInt = noData.map { $0.count }
+ /// try print(noInt.unwrap())
+ /// // Throws error
+ ///
+ /// - parameter transform: A closure that takes the success value of the `Result` instance.
+ ///
+ /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the
+ /// same failure.
+ public func map(_ transform: (Value) -> T) -> Result {
+ switch self {
+ case .success(let value):
+ return .success(transform(value))
+ case .failure(let error):
+ return .failure(error)
+ }
+ }
+
+ /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter.
+ ///
+ /// Use the `flatMap` method with a closure that may throw an error. For example:
+ ///
+ /// let possibleData: Result = .success(Data(...))
+ /// let possibleObject = possibleData.flatMap {
+ /// try JSONSerialization.jsonObject(with: $0)
+ /// }
+ ///
+ /// - parameter transform: A closure that takes the success value of the instance.
+ ///
+ /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the
+ /// same failure.
+ public func flatMap(_ transform: (Value) throws -> T) -> Result {
+ switch self {
+ case .success(let value):
+ do {
+ return try .success(transform(value))
+ } catch {
+ return .failure(error)
+ }
+ case .failure(let error):
+ return .failure(error)
+ }
+ }
+
+ /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
+ ///
+ /// Use the `mapError` function with a closure that does not throw. For example:
+ ///
+ /// let possibleData: Result = .failure(someError)
+ /// let withMyError: Result = possibleData.mapError { MyError.error($0) }
+ ///
+ /// - Parameter transform: A closure that takes the error of the instance.
+ /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns
+ /// the same instance.
+ public func mapError(_ transform: (Error) -> T) -> Result {
+ switch self {
+ case .failure(let error):
+ return .failure(transform(error))
+ case .success:
+ return self
+ }
+ }
+
+ /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
+ ///
+ /// Use the `flatMapError` function with a closure that may throw an error. For example:
+ ///
+ /// let possibleData: Result = .success(Data(...))
+ /// let possibleObject = possibleData.flatMapError {
+ /// try someFailableFunction(taking: $0)
+ /// }
+ ///
+ /// - Parameter transform: A throwing closure that takes the error of the instance.
+ ///
+ /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns
+ /// the same instance.
+ public func flatMapError(_ transform: (Error) throws -> T) -> Result {
+ switch self {
+ case .failure(let error):
+ do {
+ return try .failure(transform(error))
+ } catch {
+ return .failure(error)
+ }
+ case .success:
+ return self
+ }
+ }
+
+ /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter.
+ ///
+ /// Use the `withValue` function to evaluate the passed closure without modifying the `Result` instance.
+ ///
+ /// - Parameter closure: A closure that takes the success value of this instance.
+ /// - Returns: This `Result` instance, unmodified.
+ @discardableResult
+ public func withValue(_ closure: (Value) throws -> Void) rethrows -> Result {
+ if case let .success(value) = self { try closure(value) }
+
+ return self
+ }
+
+ /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
+ ///
+ /// Use the `withError` function to evaluate the passed closure without modifying the `Result` instance.
+ ///
+ /// - Parameter closure: A closure that takes the success value of this instance.
+ /// - Returns: This `Result` instance, unmodified.
+ @discardableResult
+ public func withError(_ closure: (Error) throws -> Void) rethrows -> Result {
+ if case let .failure(error) = self { try closure(error) }
+
+ return self
+ }
+
+ /// Evaluates the specified closure when the `Result` is a success.
+ ///
+ /// Use the `ifSuccess` function to evaluate the passed closure without modifying the `Result` instance.
+ ///
+ /// - Parameter closure: A `Void` closure.
+ /// - Returns: This `Result` instance, unmodified.
+ @discardableResult
+ public func ifSuccess(_ closure: () throws -> Void) rethrows -> Result {
+ if isSuccess { try closure() }
+
+ return self
+ }
+
+ /// Evaluates the specified closure when the `Result` is a failure.
+ ///
+ /// Use the `ifFailure` function to evaluate the passed closure without modifying the `Result` instance.
+ ///
+ /// - Parameter closure: A `Void` closure.
+ /// - Returns: This `Result` instance, unmodified.
+ @discardableResult
+ public func ifFailure(_ closure: () throws -> Void) rethrows -> Result {
+ if isFailure { try closure() }
+
+ return self
+ }
+}
diff --git a/Pods/Alamofire/Source/ServerTrustPolicy.swift b/Pods/Alamofire/Source/ServerTrustPolicy.swift
new file mode 100644
index 0000000..dea099e
--- /dev/null
+++ b/Pods/Alamofire/Source/ServerTrustPolicy.swift
@@ -0,0 +1,307 @@
+//
+// ServerTrustPolicy.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// Responsible for managing the mapping of `ServerTrustPolicy` objects to a given host.
+open class ServerTrustPolicyManager {
+ /// The dictionary of policies mapped to a particular host.
+ public let policies: [String: ServerTrustPolicy]
+
+ /// Initializes the `ServerTrustPolicyManager` instance with the given policies.
+ ///
+ /// Since different servers and web services can have different leaf certificates, intermediate and even root
+ /// certficates, it is important to have the flexibility to specify evaluation policies on a per host basis. This
+ /// allows for scenarios such as using default evaluation for host1, certificate pinning for host2, public key
+ /// pinning for host3 and disabling evaluation for host4.
+ ///
+ /// - parameter policies: A dictionary of all policies mapped to a particular host.
+ ///
+ /// - returns: The new `ServerTrustPolicyManager` instance.
+ public init(policies: [String: ServerTrustPolicy]) {
+ self.policies = policies
+ }
+
+ /// Returns the `ServerTrustPolicy` for the given host if applicable.
+ ///
+ /// By default, this method will return the policy that perfectly matches the given host. Subclasses could override
+ /// this method and implement more complex mapping implementations such as wildcards.
+ ///
+ /// - parameter host: The host to use when searching for a matching policy.
+ ///
+ /// - returns: The server trust policy for the given host if found.
+ open func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? {
+ return policies[host]
+ }
+}
+
+// MARK: -
+
+extension URLSession {
+ private struct AssociatedKeys {
+ static var managerKey = "URLSession.ServerTrustPolicyManager"
+ }
+
+ var serverTrustPolicyManager: ServerTrustPolicyManager? {
+ get {
+ return objc_getAssociatedObject(self, &AssociatedKeys.managerKey) as? ServerTrustPolicyManager
+ }
+ set (manager) {
+ objc_setAssociatedObject(self, &AssociatedKeys.managerKey, manager, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+ }
+ }
+}
+
+// MARK: - ServerTrustPolicy
+
+/// The `ServerTrustPolicy` evaluates the server trust generally provided by an `NSURLAuthenticationChallenge` when
+/// connecting to a server over a secure HTTPS connection. The policy configuration then evaluates the server trust
+/// with a given set of criteria to determine whether the server trust is valid and the connection should be made.
+///
+/// Using pinned certificates or public keys for evaluation helps prevent man-in-the-middle (MITM) attacks and other
+/// vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged
+/// to route all communication over an HTTPS connection with pinning enabled.
+///
+/// - performDefaultEvaluation: Uses the default server trust evaluation while allowing you to control whether to
+/// validate the host provided by the challenge. Applications are encouraged to always
+/// validate the host in production environments to guarantee the validity of the server's
+/// certificate chain.
+///
+/// - performRevokedEvaluation: Uses the default and revoked server trust evaluations allowing you to control whether to
+/// validate the host provided by the challenge as well as specify the revocation flags for
+/// testing for revoked certificates. Apple platforms did not start testing for revoked
+/// certificates automatically until iOS 10.1, macOS 10.12 and tvOS 10.1 which is
+/// demonstrated in our TLS tests. Applications are encouraged to always validate the host
+/// in production environments to guarantee the validity of the server's certificate chain.
+///
+/// - pinCertificates: Uses the pinned certificates to validate the server trust. The server trust is
+/// considered valid if one of the pinned certificates match one of the server certificates.
+/// By validating both the certificate chain and host, certificate pinning provides a very
+/// secure form of server trust validation mitigating most, if not all, MITM attacks.
+/// Applications are encouraged to always validate the host and require a valid certificate
+/// chain in production environments.
+///
+/// - pinPublicKeys: Uses the pinned public keys to validate the server trust. The server trust is considered
+/// valid if one of the pinned public keys match one of the server certificate public keys.
+/// By validating both the certificate chain and host, public key pinning provides a very
+/// secure form of server trust validation mitigating most, if not all, MITM attacks.
+/// Applications are encouraged to always validate the host and require a valid certificate
+/// chain in production environments.
+///
+/// - disableEvaluation: Disables all evaluation which in turn will always consider any server trust as valid.
+///
+/// - customEvaluation: Uses the associated closure to evaluate the validity of the server trust.
+public enum ServerTrustPolicy {
+ case performDefaultEvaluation(validateHost: Bool)
+ case performRevokedEvaluation(validateHost: Bool, revocationFlags: CFOptionFlags)
+ case pinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool)
+ case pinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool)
+ case disableEvaluation
+ case customEvaluation((_ serverTrust: SecTrust, _ host: String) -> Bool)
+
+ // MARK: - Bundle Location
+
+ /// Returns all certificates within the given bundle with a `.cer` file extension.
+ ///
+ /// - parameter bundle: The bundle to search for all `.cer` files.
+ ///
+ /// - returns: All certificates within the given bundle.
+ public static func certificates(in bundle: Bundle = Bundle.main) -> [SecCertificate] {
+ var certificates: [SecCertificate] = []
+
+ let paths = Set([".cer", ".CER", ".crt", ".CRT", ".der", ".DER"].map { fileExtension in
+ bundle.paths(forResourcesOfType: fileExtension, inDirectory: nil)
+ }.joined())
+
+ for path in paths {
+ if
+ let certificateData = try? Data(contentsOf: URL(fileURLWithPath: path)) as CFData,
+ let certificate = SecCertificateCreateWithData(nil, certificateData)
+ {
+ certificates.append(certificate)
+ }
+ }
+
+ return certificates
+ }
+
+ /// Returns all public keys within the given bundle with a `.cer` file extension.
+ ///
+ /// - parameter bundle: The bundle to search for all `*.cer` files.
+ ///
+ /// - returns: All public keys within the given bundle.
+ public static func publicKeys(in bundle: Bundle = Bundle.main) -> [SecKey] {
+ var publicKeys: [SecKey] = []
+
+ for certificate in certificates(in: bundle) {
+ if let publicKey = publicKey(for: certificate) {
+ publicKeys.append(publicKey)
+ }
+ }
+
+ return publicKeys
+ }
+
+ // MARK: - Evaluation
+
+ /// Evaluates whether the server trust is valid for the given host.
+ ///
+ /// - parameter serverTrust: The server trust to evaluate.
+ /// - parameter host: The host of the challenge protection space.
+ ///
+ /// - returns: Whether the server trust is valid.
+ public func evaluate(_ serverTrust: SecTrust, forHost host: String) -> Bool {
+ var serverTrustIsValid = false
+
+ switch self {
+ case let .performDefaultEvaluation(validateHost):
+ let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil)
+ SecTrustSetPolicies(serverTrust, policy)
+
+ serverTrustIsValid = trustIsValid(serverTrust)
+ case let .performRevokedEvaluation(validateHost, revocationFlags):
+ let defaultPolicy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil)
+ let revokedPolicy = SecPolicyCreateRevocation(revocationFlags)
+ SecTrustSetPolicies(serverTrust, [defaultPolicy, revokedPolicy] as CFTypeRef)
+
+ serverTrustIsValid = trustIsValid(serverTrust)
+ case let .pinCertificates(pinnedCertificates, validateCertificateChain, validateHost):
+ if validateCertificateChain {
+ let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil)
+ SecTrustSetPolicies(serverTrust, policy)
+
+ SecTrustSetAnchorCertificates(serverTrust, pinnedCertificates as CFArray)
+ SecTrustSetAnchorCertificatesOnly(serverTrust, true)
+
+ serverTrustIsValid = trustIsValid(serverTrust)
+ } else {
+ let serverCertificatesDataArray = certificateData(for: serverTrust)
+ let pinnedCertificatesDataArray = certificateData(for: pinnedCertificates)
+
+ outerLoop: for serverCertificateData in serverCertificatesDataArray {
+ for pinnedCertificateData in pinnedCertificatesDataArray {
+ if serverCertificateData == pinnedCertificateData {
+ serverTrustIsValid = true
+ break outerLoop
+ }
+ }
+ }
+ }
+ case let .pinPublicKeys(pinnedPublicKeys, validateCertificateChain, validateHost):
+ var certificateChainEvaluationPassed = true
+
+ if validateCertificateChain {
+ let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil)
+ SecTrustSetPolicies(serverTrust, policy)
+
+ certificateChainEvaluationPassed = trustIsValid(serverTrust)
+ }
+
+ if certificateChainEvaluationPassed {
+ outerLoop: for serverPublicKey in ServerTrustPolicy.publicKeys(for: serverTrust) as [AnyObject] {
+ for pinnedPublicKey in pinnedPublicKeys as [AnyObject] {
+ if serverPublicKey.isEqual(pinnedPublicKey) {
+ serverTrustIsValid = true
+ break outerLoop
+ }
+ }
+ }
+ }
+ case .disableEvaluation:
+ serverTrustIsValid = true
+ case let .customEvaluation(closure):
+ serverTrustIsValid = closure(serverTrust, host)
+ }
+
+ return serverTrustIsValid
+ }
+
+ // MARK: - Private - Trust Validation
+
+ private func trustIsValid(_ trust: SecTrust) -> Bool {
+ var isValid = false
+
+ var result = SecTrustResultType.invalid
+ let status = SecTrustEvaluate(trust, &result)
+
+ if status == errSecSuccess {
+ let unspecified = SecTrustResultType.unspecified
+ let proceed = SecTrustResultType.proceed
+
+
+ isValid = result == unspecified || result == proceed
+ }
+
+ return isValid
+ }
+
+ // MARK: - Private - Certificate Data
+
+ private func certificateData(for trust: SecTrust) -> [Data] {
+ var certificates: [SecCertificate] = []
+
+ for index in 0.. [Data] {
+ return certificates.map { SecCertificateCopyData($0) as Data }
+ }
+
+ // MARK: - Private - Public Key Extraction
+
+ private static func publicKeys(for trust: SecTrust) -> [SecKey] {
+ var publicKeys: [SecKey] = []
+
+ for index in 0.. SecKey? {
+ var publicKey: SecKey?
+
+ let policy = SecPolicyCreateBasicX509()
+ var trust: SecTrust?
+ let trustCreationStatus = SecTrustCreateWithCertificates(certificate, policy, &trust)
+
+ if let trust = trust, trustCreationStatus == errSecSuccess {
+ publicKey = SecTrustCopyPublicKey(trust)
+ }
+
+ return publicKey
+ }
+}
diff --git a/Pods/Alamofire/Source/SessionDelegate.swift b/Pods/Alamofire/Source/SessionDelegate.swift
new file mode 100644
index 0000000..4964f1e
--- /dev/null
+++ b/Pods/Alamofire/Source/SessionDelegate.swift
@@ -0,0 +1,725 @@
+//
+// SessionDelegate.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// Responsible for handling all delegate callbacks for the underlying session.
+open class SessionDelegate: NSObject {
+
+ // MARK: URLSessionDelegate Overrides
+
+ /// Overrides default behavior for URLSessionDelegate method `urlSession(_:didBecomeInvalidWithError:)`.
+ open var sessionDidBecomeInvalidWithError: ((URLSession, Error?) -> Void)?
+
+ /// Overrides default behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)`.
+ open var sessionDidReceiveChallenge: ((URLSession, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?
+
+ /// Overrides all behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)` and requires the caller to call the `completionHandler`.
+ open var sessionDidReceiveChallengeWithCompletion: ((URLSession, URLAuthenticationChallenge, @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void)?
+
+ /// Overrides default behavior for URLSessionDelegate method `urlSessionDidFinishEvents(forBackgroundURLSession:)`.
+ open var sessionDidFinishEventsForBackgroundURLSession: ((URLSession) -> Void)?
+
+ // MARK: URLSessionTaskDelegate Overrides
+
+ /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)`.
+ open var taskWillPerformHTTPRedirection: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest) -> URLRequest?)?
+
+ /// Overrides all behavior for URLSessionTaskDelegate method `urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)` and
+ /// requires the caller to call the `completionHandler`.
+ open var taskWillPerformHTTPRedirectionWithCompletion: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest, @escaping (URLRequest?) -> Void) -> Void)?
+
+ /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:didReceive:completionHandler:)`.
+ open var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?
+
+ /// Overrides all behavior for URLSessionTaskDelegate method `urlSession(_:task:didReceive:completionHandler:)` and
+ /// requires the caller to call the `completionHandler`.
+ open var taskDidReceiveChallengeWithCompletion: ((URLSession, URLSessionTask, URLAuthenticationChallenge, @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void)?
+
+ /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:needNewBodyStream:)`.
+ open var taskNeedNewBodyStream: ((URLSession, URLSessionTask) -> InputStream?)?
+
+ /// Overrides all behavior for URLSessionTaskDelegate method `urlSession(_:task:needNewBodyStream:)` and
+ /// requires the caller to call the `completionHandler`.
+ open var taskNeedNewBodyStreamWithCompletion: ((URLSession, URLSessionTask, @escaping (InputStream?) -> Void) -> Void)?
+
+ /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)`.
+ open var taskDidSendBodyData: ((URLSession, URLSessionTask, Int64, Int64, Int64) -> Void)?
+
+ /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:didCompleteWithError:)`.
+ open var taskDidComplete: ((URLSession, URLSessionTask, Error?) -> Void)?
+
+ // MARK: URLSessionDataDelegate Overrides
+
+ /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didReceive:completionHandler:)`.
+ open var dataTaskDidReceiveResponse: ((URLSession, URLSessionDataTask, URLResponse) -> URLSession.ResponseDisposition)?
+
+ /// Overrides all behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didReceive:completionHandler:)` and
+ /// requires caller to call the `completionHandler`.
+ open var dataTaskDidReceiveResponseWithCompletion: ((URLSession, URLSessionDataTask, URLResponse, @escaping (URLSession.ResponseDisposition) -> Void) -> Void)?
+
+ /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didBecome:)`.
+ open var dataTaskDidBecomeDownloadTask: ((URLSession, URLSessionDataTask, URLSessionDownloadTask) -> Void)?
+
+ /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didReceive:)`.
+ open var dataTaskDidReceiveData: ((URLSession, URLSessionDataTask, Data) -> Void)?
+
+ /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:willCacheResponse:completionHandler:)`.
+ open var dataTaskWillCacheResponse: ((URLSession, URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)?
+
+ /// Overrides all behavior for URLSessionDataDelegate method `urlSession(_:dataTask:willCacheResponse:completionHandler:)` and
+ /// requires caller to call the `completionHandler`.
+ open var dataTaskWillCacheResponseWithCompletion: ((URLSession, URLSessionDataTask, CachedURLResponse, @escaping (CachedURLResponse?) -> Void) -> Void)?
+
+ // MARK: URLSessionDownloadDelegate Overrides
+
+ /// Overrides default behavior for URLSessionDownloadDelegate method `urlSession(_:downloadTask:didFinishDownloadingTo:)`.
+ open var downloadTaskDidFinishDownloadingToURL: ((URLSession, URLSessionDownloadTask, URL) -> Void)?
+
+ /// Overrides default behavior for URLSessionDownloadDelegate method `urlSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)`.
+ open var downloadTaskDidWriteData: ((URLSession, URLSessionDownloadTask, Int64, Int64, Int64) -> Void)?
+
+ /// Overrides default behavior for URLSessionDownloadDelegate method `urlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:)`.
+ open var downloadTaskDidResumeAtOffset: ((URLSession, URLSessionDownloadTask, Int64, Int64) -> Void)?
+
+ // MARK: URLSessionStreamDelegate Overrides
+
+#if !os(watchOS)
+
+ /// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:readClosedFor:)`.
+ @available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+ open var streamTaskReadClosed: ((URLSession, URLSessionStreamTask) -> Void)? {
+ get {
+ return _streamTaskReadClosed as? (URLSession, URLSessionStreamTask) -> Void
+ }
+ set {
+ _streamTaskReadClosed = newValue
+ }
+ }
+
+ /// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:writeClosedFor:)`.
+ @available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+ open var streamTaskWriteClosed: ((URLSession, URLSessionStreamTask) -> Void)? {
+ get {
+ return _streamTaskWriteClosed as? (URLSession, URLSessionStreamTask) -> Void
+ }
+ set {
+ _streamTaskWriteClosed = newValue
+ }
+ }
+
+ /// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:betterRouteDiscoveredFor:)`.
+ @available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+ open var streamTaskBetterRouteDiscovered: ((URLSession, URLSessionStreamTask) -> Void)? {
+ get {
+ return _streamTaskBetterRouteDiscovered as? (URLSession, URLSessionStreamTask) -> Void
+ }
+ set {
+ _streamTaskBetterRouteDiscovered = newValue
+ }
+ }
+
+ /// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:streamTask:didBecome:outputStream:)`.
+ @available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+ open var streamTaskDidBecomeInputAndOutputStreams: ((URLSession, URLSessionStreamTask, InputStream, OutputStream) -> Void)? {
+ get {
+ return _streamTaskDidBecomeInputStream as? (URLSession, URLSessionStreamTask, InputStream, OutputStream) -> Void
+ }
+ set {
+ _streamTaskDidBecomeInputStream = newValue
+ }
+ }
+
+ var _streamTaskReadClosed: Any?
+ var _streamTaskWriteClosed: Any?
+ var _streamTaskBetterRouteDiscovered: Any?
+ var _streamTaskDidBecomeInputStream: Any?
+
+#endif
+
+ // MARK: Properties
+
+ var retrier: RequestRetrier?
+ weak var sessionManager: SessionManager?
+
+ var requests: [Int: Request] = [:]
+ private let lock = NSLock()
+
+ /// Access the task delegate for the specified task in a thread-safe manner.
+ open subscript(task: URLSessionTask) -> Request? {
+ get {
+ lock.lock() ; defer { lock.unlock() }
+ return requests[task.taskIdentifier]
+ }
+ set {
+ lock.lock() ; defer { lock.unlock() }
+ requests[task.taskIdentifier] = newValue
+ }
+ }
+
+ // MARK: Lifecycle
+
+ /// Initializes the `SessionDelegate` instance.
+ ///
+ /// - returns: The new `SessionDelegate` instance.
+ public override init() {
+ super.init()
+ }
+
+ // MARK: NSObject Overrides
+
+ /// Returns a `Bool` indicating whether the `SessionDelegate` implements or inherits a method that can respond
+ /// to a specified message.
+ ///
+ /// - parameter selector: A selector that identifies a message.
+ ///
+ /// - returns: `true` if the receiver implements or inherits a method that can respond to selector, otherwise `false`.
+ open override func responds(to selector: Selector) -> Bool {
+ #if !os(macOS)
+ if selector == #selector(URLSessionDelegate.urlSessionDidFinishEvents(forBackgroundURLSession:)) {
+ return sessionDidFinishEventsForBackgroundURLSession != nil
+ }
+ #endif
+
+ #if !os(watchOS)
+ if #available(iOS 9.0, macOS 10.11, tvOS 9.0, *) {
+ switch selector {
+ case #selector(URLSessionStreamDelegate.urlSession(_:readClosedFor:)):
+ return streamTaskReadClosed != nil
+ case #selector(URLSessionStreamDelegate.urlSession(_:writeClosedFor:)):
+ return streamTaskWriteClosed != nil
+ case #selector(URLSessionStreamDelegate.urlSession(_:betterRouteDiscoveredFor:)):
+ return streamTaskBetterRouteDiscovered != nil
+ case #selector(URLSessionStreamDelegate.urlSession(_:streamTask:didBecome:outputStream:)):
+ return streamTaskDidBecomeInputAndOutputStreams != nil
+ default:
+ break
+ }
+ }
+ #endif
+
+ switch selector {
+ case #selector(URLSessionDelegate.urlSession(_:didBecomeInvalidWithError:)):
+ return sessionDidBecomeInvalidWithError != nil
+ case #selector(URLSessionDelegate.urlSession(_:didReceive:completionHandler:)):
+ return (sessionDidReceiveChallenge != nil || sessionDidReceiveChallengeWithCompletion != nil)
+ case #selector(URLSessionTaskDelegate.urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)):
+ return (taskWillPerformHTTPRedirection != nil || taskWillPerformHTTPRedirectionWithCompletion != nil)
+ case #selector(URLSessionDataDelegate.urlSession(_:dataTask:didReceive:completionHandler:)):
+ return (dataTaskDidReceiveResponse != nil || dataTaskDidReceiveResponseWithCompletion != nil)
+ default:
+ return type(of: self).instancesRespond(to: selector)
+ }
+ }
+}
+
+// MARK: - URLSessionDelegate
+
+extension SessionDelegate: URLSessionDelegate {
+ /// Tells the delegate that the session has been invalidated.
+ ///
+ /// - parameter session: The session object that was invalidated.
+ /// - parameter error: The error that caused invalidation, or nil if the invalidation was explicit.
+ open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
+ sessionDidBecomeInvalidWithError?(session, error)
+ }
+
+ /// Requests credentials from the delegate in response to a session-level authentication request from the
+ /// remote server.
+ ///
+ /// - parameter session: The session containing the task that requested authentication.
+ /// - parameter challenge: An object that contains the request for authentication.
+ /// - parameter completionHandler: A handler that your delegate method must call providing the disposition
+ /// and credential.
+ open func urlSession(
+ _ session: URLSession,
+ didReceive challenge: URLAuthenticationChallenge,
+ completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
+ {
+ guard sessionDidReceiveChallengeWithCompletion == nil else {
+ sessionDidReceiveChallengeWithCompletion?(session, challenge, completionHandler)
+ return
+ }
+
+ var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
+ var credential: URLCredential?
+
+ if let sessionDidReceiveChallenge = sessionDidReceiveChallenge {
+ (disposition, credential) = sessionDidReceiveChallenge(session, challenge)
+ } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
+ let host = challenge.protectionSpace.host
+
+ if
+ let serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicy(forHost: host),
+ let serverTrust = challenge.protectionSpace.serverTrust
+ {
+ if serverTrustPolicy.evaluate(serverTrust, forHost: host) {
+ disposition = .useCredential
+ credential = URLCredential(trust: serverTrust)
+ } else {
+ disposition = .cancelAuthenticationChallenge
+ }
+ }
+ }
+
+ completionHandler(disposition, credential)
+ }
+
+#if !os(macOS)
+
+ /// Tells the delegate that all messages enqueued for a session have been delivered.
+ ///
+ /// - parameter session: The session that no longer has any outstanding requests.
+ open func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
+ sessionDidFinishEventsForBackgroundURLSession?(session)
+ }
+
+#endif
+}
+
+// MARK: - URLSessionTaskDelegate
+
+extension SessionDelegate: URLSessionTaskDelegate {
+ /// Tells the delegate that the remote server requested an HTTP redirect.
+ ///
+ /// - parameter session: The session containing the task whose request resulted in a redirect.
+ /// - parameter task: The task whose request resulted in a redirect.
+ /// - parameter response: An object containing the server’s response to the original request.
+ /// - parameter request: A URL request object filled out with the new location.
+ /// - parameter completionHandler: A closure that your handler should call with either the value of the request
+ /// parameter, a modified URL request object, or NULL to refuse the redirect and
+ /// return the body of the redirect response.
+ open func urlSession(
+ _ session: URLSession,
+ task: URLSessionTask,
+ willPerformHTTPRedirection response: HTTPURLResponse,
+ newRequest request: URLRequest,
+ completionHandler: @escaping (URLRequest?) -> Void)
+ {
+ guard taskWillPerformHTTPRedirectionWithCompletion == nil else {
+ taskWillPerformHTTPRedirectionWithCompletion?(session, task, response, request, completionHandler)
+ return
+ }
+
+ var redirectRequest: URLRequest? = request
+
+ if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection {
+ redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request)
+ }
+
+ completionHandler(redirectRequest)
+ }
+
+ /// Requests credentials from the delegate in response to an authentication request from the remote server.
+ ///
+ /// - parameter session: The session containing the task whose request requires authentication.
+ /// - parameter task: The task whose request requires authentication.
+ /// - parameter challenge: An object that contains the request for authentication.
+ /// - parameter completionHandler: A handler that your delegate method must call providing the disposition
+ /// and credential.
+ open func urlSession(
+ _ session: URLSession,
+ task: URLSessionTask,
+ didReceive challenge: URLAuthenticationChallenge,
+ completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
+ {
+ guard taskDidReceiveChallengeWithCompletion == nil else {
+ taskDidReceiveChallengeWithCompletion?(session, task, challenge, completionHandler)
+ return
+ }
+
+ if let taskDidReceiveChallenge = taskDidReceiveChallenge {
+ let result = taskDidReceiveChallenge(session, task, challenge)
+ completionHandler(result.0, result.1)
+ } else if let delegate = self[task]?.delegate {
+ delegate.urlSession(
+ session,
+ task: task,
+ didReceive: challenge,
+ completionHandler: completionHandler
+ )
+ } else {
+ urlSession(session, didReceive: challenge, completionHandler: completionHandler)
+ }
+ }
+
+ /// Tells the delegate when a task requires a new request body stream to send to the remote server.
+ ///
+ /// - parameter session: The session containing the task that needs a new body stream.
+ /// - parameter task: The task that needs a new body stream.
+ /// - parameter completionHandler: A completion handler that your delegate method should call with the new body stream.
+ open func urlSession(
+ _ session: URLSession,
+ task: URLSessionTask,
+ needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)
+ {
+ guard taskNeedNewBodyStreamWithCompletion == nil else {
+ taskNeedNewBodyStreamWithCompletion?(session, task, completionHandler)
+ return
+ }
+
+ if let taskNeedNewBodyStream = taskNeedNewBodyStream {
+ completionHandler(taskNeedNewBodyStream(session, task))
+ } else if let delegate = self[task]?.delegate {
+ delegate.urlSession(session, task: task, needNewBodyStream: completionHandler)
+ }
+ }
+
+ /// Periodically informs the delegate of the progress of sending body content to the server.
+ ///
+ /// - parameter session: The session containing the data task.
+ /// - parameter task: The data task.
+ /// - parameter bytesSent: The number of bytes sent since the last time this delegate method was called.
+ /// - parameter totalBytesSent: The total number of bytes sent so far.
+ /// - parameter totalBytesExpectedToSend: The expected length of the body data.
+ open func urlSession(
+ _ session: URLSession,
+ task: URLSessionTask,
+ didSendBodyData bytesSent: Int64,
+ totalBytesSent: Int64,
+ totalBytesExpectedToSend: Int64)
+ {
+ if let taskDidSendBodyData = taskDidSendBodyData {
+ taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend)
+ } else if let delegate = self[task]?.delegate as? UploadTaskDelegate {
+ delegate.URLSession(
+ session,
+ task: task,
+ didSendBodyData: bytesSent,
+ totalBytesSent: totalBytesSent,
+ totalBytesExpectedToSend: totalBytesExpectedToSend
+ )
+ }
+ }
+
+#if !os(watchOS)
+
+ /// Tells the delegate that the session finished collecting metrics for the task.
+ ///
+ /// - parameter session: The session collecting the metrics.
+ /// - parameter task: The task whose metrics have been collected.
+ /// - parameter metrics: The collected metrics.
+ @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
+ @objc(URLSession:task:didFinishCollectingMetrics:)
+ open func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {
+ self[task]?.delegate.metrics = metrics
+ }
+
+#endif
+
+ /// Tells the delegate that the task finished transferring data.
+ ///
+ /// - parameter session: The session containing the task whose request finished transferring data.
+ /// - parameter task: The task whose request finished transferring data.
+ /// - parameter error: If an error occurred, an error object indicating how the transfer failed, otherwise nil.
+ open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
+ /// Executed after it is determined that the request is not going to be retried
+ let completeTask: (URLSession, URLSessionTask, Error?) -> Void = { [weak self] session, task, error in
+ guard let strongSelf = self else { return }
+
+ strongSelf.taskDidComplete?(session, task, error)
+
+ strongSelf[task]?.delegate.urlSession(session, task: task, didCompleteWithError: error)
+
+ var userInfo: [String: Any] = [Notification.Key.Task: task]
+
+ if let data = (strongSelf[task]?.delegate as? DataTaskDelegate)?.data {
+ userInfo[Notification.Key.ResponseData] = data
+ }
+
+ NotificationCenter.default.post(
+ name: Notification.Name.Task.DidComplete,
+ object: strongSelf,
+ userInfo: userInfo
+ )
+
+ strongSelf[task] = nil
+ }
+
+ guard let request = self[task], let sessionManager = sessionManager else {
+ completeTask(session, task, error)
+ return
+ }
+
+ // Run all validations on the request before checking if an error occurred
+ request.validations.forEach { $0() }
+
+ // Determine whether an error has occurred
+ var error: Error? = error
+
+ if request.delegate.error != nil {
+ error = request.delegate.error
+ }
+
+ /// If an error occurred and the retrier is set, asynchronously ask the retrier if the request
+ /// should be retried. Otherwise, complete the task by notifying the task delegate.
+ if let retrier = retrier, let error = error {
+ retrier.should(sessionManager, retry: request, with: error) { [weak self] shouldRetry, timeDelay in
+ guard shouldRetry else { completeTask(session, task, error) ; return }
+
+ DispatchQueue.utility.after(timeDelay) { [weak self] in
+ guard let strongSelf = self else { return }
+
+ let retrySucceeded = strongSelf.sessionManager?.retry(request) ?? false
+
+ if retrySucceeded, let task = request.task {
+ strongSelf[task] = request
+ return
+ } else {
+ completeTask(session, task, error)
+ }
+ }
+ }
+ } else {
+ completeTask(session, task, error)
+ }
+ }
+}
+
+// MARK: - URLSessionDataDelegate
+
+extension SessionDelegate: URLSessionDataDelegate {
+ /// Tells the delegate that the data task received the initial reply (headers) from the server.
+ ///
+ /// - parameter session: The session containing the data task that received an initial reply.
+ /// - parameter dataTask: The data task that received an initial reply.
+ /// - parameter response: A URL response object populated with headers.
+ /// - parameter completionHandler: A completion handler that your code calls to continue the transfer, passing a
+ /// constant to indicate whether the transfer should continue as a data task or
+ /// should become a download task.
+ open func urlSession(
+ _ session: URLSession,
+ dataTask: URLSessionDataTask,
+ didReceive response: URLResponse,
+ completionHandler: @escaping (URLSession.ResponseDisposition) -> Void)
+ {
+ guard dataTaskDidReceiveResponseWithCompletion == nil else {
+ dataTaskDidReceiveResponseWithCompletion?(session, dataTask, response, completionHandler)
+ return
+ }
+
+ var disposition: URLSession.ResponseDisposition = .allow
+
+ if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse {
+ disposition = dataTaskDidReceiveResponse(session, dataTask, response)
+ }
+
+ completionHandler(disposition)
+ }
+
+ /// Tells the delegate that the data task was changed to a download task.
+ ///
+ /// - parameter session: The session containing the task that was replaced by a download task.
+ /// - parameter dataTask: The data task that was replaced by a download task.
+ /// - parameter downloadTask: The new download task that replaced the data task.
+ open func urlSession(
+ _ session: URLSession,
+ dataTask: URLSessionDataTask,
+ didBecome downloadTask: URLSessionDownloadTask)
+ {
+ if let dataTaskDidBecomeDownloadTask = dataTaskDidBecomeDownloadTask {
+ dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask)
+ } else {
+ self[downloadTask]?.delegate = DownloadTaskDelegate(task: downloadTask)
+ }
+ }
+
+ /// Tells the delegate that the data task has received some of the expected data.
+ ///
+ /// - parameter session: The session containing the data task that provided data.
+ /// - parameter dataTask: The data task that provided data.
+ /// - parameter data: A data object containing the transferred data.
+ open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
+ if let dataTaskDidReceiveData = dataTaskDidReceiveData {
+ dataTaskDidReceiveData(session, dataTask, data)
+ } else if let delegate = self[dataTask]?.delegate as? DataTaskDelegate {
+ delegate.urlSession(session, dataTask: dataTask, didReceive: data)
+ }
+ }
+
+ /// Asks the delegate whether the data (or upload) task should store the response in the cache.
+ ///
+ /// - parameter session: The session containing the data (or upload) task.
+ /// - parameter dataTask: The data (or upload) task.
+ /// - parameter proposedResponse: The default caching behavior. This behavior is determined based on the current
+ /// caching policy and the values of certain received headers, such as the Pragma
+ /// and Cache-Control headers.
+ /// - parameter completionHandler: A block that your handler must call, providing either the original proposed
+ /// response, a modified version of that response, or NULL to prevent caching the
+ /// response. If your delegate implements this method, it must call this completion
+ /// handler; otherwise, your app leaks memory.
+ open func urlSession(
+ _ session: URLSession,
+ dataTask: URLSessionDataTask,
+ willCacheResponse proposedResponse: CachedURLResponse,
+ completionHandler: @escaping (CachedURLResponse?) -> Void)
+ {
+ guard dataTaskWillCacheResponseWithCompletion == nil else {
+ dataTaskWillCacheResponseWithCompletion?(session, dataTask, proposedResponse, completionHandler)
+ return
+ }
+
+ if let dataTaskWillCacheResponse = dataTaskWillCacheResponse {
+ completionHandler(dataTaskWillCacheResponse(session, dataTask, proposedResponse))
+ } else if let delegate = self[dataTask]?.delegate as? DataTaskDelegate {
+ delegate.urlSession(
+ session,
+ dataTask: dataTask,
+ willCacheResponse: proposedResponse,
+ completionHandler: completionHandler
+ )
+ } else {
+ completionHandler(proposedResponse)
+ }
+ }
+}
+
+// MARK: - URLSessionDownloadDelegate
+
+extension SessionDelegate: URLSessionDownloadDelegate {
+ /// Tells the delegate that a download task has finished downloading.
+ ///
+ /// - parameter session: The session containing the download task that finished.
+ /// - parameter downloadTask: The download task that finished.
+ /// - parameter location: A file URL for the temporary file. Because the file is temporary, you must either
+ /// open the file for reading or move it to a permanent location in your app’s sandbox
+ /// container directory before returning from this delegate method.
+ open func urlSession(
+ _ session: URLSession,
+ downloadTask: URLSessionDownloadTask,
+ didFinishDownloadingTo location: URL)
+ {
+ if let downloadTaskDidFinishDownloadingToURL = downloadTaskDidFinishDownloadingToURL {
+ downloadTaskDidFinishDownloadingToURL(session, downloadTask, location)
+ } else if let delegate = self[downloadTask]?.delegate as? DownloadTaskDelegate {
+ delegate.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location)
+ }
+ }
+
+ /// Periodically informs the delegate about the download’s progress.
+ ///
+ /// - parameter session: The session containing the download task.
+ /// - parameter downloadTask: The download task.
+ /// - parameter bytesWritten: The number of bytes transferred since the last time this delegate
+ /// method was called.
+ /// - parameter totalBytesWritten: The total number of bytes transferred so far.
+ /// - parameter totalBytesExpectedToWrite: The expected length of the file, as provided by the Content-Length
+ /// header. If this header was not provided, the value is
+ /// `NSURLSessionTransferSizeUnknown`.
+ open func urlSession(
+ _ session: URLSession,
+ downloadTask: URLSessionDownloadTask,
+ didWriteData bytesWritten: Int64,
+ totalBytesWritten: Int64,
+ totalBytesExpectedToWrite: Int64)
+ {
+ if let downloadTaskDidWriteData = downloadTaskDidWriteData {
+ downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
+ } else if let delegate = self[downloadTask]?.delegate as? DownloadTaskDelegate {
+ delegate.urlSession(
+ session,
+ downloadTask: downloadTask,
+ didWriteData: bytesWritten,
+ totalBytesWritten: totalBytesWritten,
+ totalBytesExpectedToWrite: totalBytesExpectedToWrite
+ )
+ }
+ }
+
+ /// Tells the delegate that the download task has resumed downloading.
+ ///
+ /// - parameter session: The session containing the download task that finished.
+ /// - parameter downloadTask: The download task that resumed. See explanation in the discussion.
+ /// - parameter fileOffset: If the file's cache policy or last modified date prevents reuse of the
+ /// existing content, then this value is zero. Otherwise, this value is an
+ /// integer representing the number of bytes on disk that do not need to be
+ /// retrieved again.
+ /// - parameter expectedTotalBytes: The expected length of the file, as provided by the Content-Length header.
+ /// If this header was not provided, the value is NSURLSessionTransferSizeUnknown.
+ open func urlSession(
+ _ session: URLSession,
+ downloadTask: URLSessionDownloadTask,
+ didResumeAtOffset fileOffset: Int64,
+ expectedTotalBytes: Int64)
+ {
+ if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset {
+ downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes)
+ } else if let delegate = self[downloadTask]?.delegate as? DownloadTaskDelegate {
+ delegate.urlSession(
+ session,
+ downloadTask: downloadTask,
+ didResumeAtOffset: fileOffset,
+ expectedTotalBytes: expectedTotalBytes
+ )
+ }
+ }
+}
+
+// MARK: - URLSessionStreamDelegate
+
+#if !os(watchOS)
+
+@available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+extension SessionDelegate: URLSessionStreamDelegate {
+ /// Tells the delegate that the read side of the connection has been closed.
+ ///
+ /// - parameter session: The session.
+ /// - parameter streamTask: The stream task.
+ open func urlSession(_ session: URLSession, readClosedFor streamTask: URLSessionStreamTask) {
+ streamTaskReadClosed?(session, streamTask)
+ }
+
+ /// Tells the delegate that the write side of the connection has been closed.
+ ///
+ /// - parameter session: The session.
+ /// - parameter streamTask: The stream task.
+ open func urlSession(_ session: URLSession, writeClosedFor streamTask: URLSessionStreamTask) {
+ streamTaskWriteClosed?(session, streamTask)
+ }
+
+ /// Tells the delegate that the system has determined that a better route to the host is available.
+ ///
+ /// - parameter session: The session.
+ /// - parameter streamTask: The stream task.
+ open func urlSession(_ session: URLSession, betterRouteDiscoveredFor streamTask: URLSessionStreamTask) {
+ streamTaskBetterRouteDiscovered?(session, streamTask)
+ }
+
+ /// Tells the delegate that the stream task has been completed and provides the unopened stream objects.
+ ///
+ /// - parameter session: The session.
+ /// - parameter streamTask: The stream task.
+ /// - parameter inputStream: The new input stream.
+ /// - parameter outputStream: The new output stream.
+ open func urlSession(
+ _ session: URLSession,
+ streamTask: URLSessionStreamTask,
+ didBecome inputStream: InputStream,
+ outputStream: OutputStream)
+ {
+ streamTaskDidBecomeInputAndOutputStreams?(session, streamTask, inputStream, outputStream)
+ }
+}
+
+#endif
diff --git a/Pods/Alamofire/Source/SessionManager.swift b/Pods/Alamofire/Source/SessionManager.swift
new file mode 100644
index 0000000..02c36a7
--- /dev/null
+++ b/Pods/Alamofire/Source/SessionManager.swift
@@ -0,0 +1,899 @@
+//
+// SessionManager.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// Responsible for creating and managing `Request` objects, as well as their underlying `NSURLSession`.
+open class SessionManager {
+
+ // MARK: - Helper Types
+
+ /// Defines whether the `MultipartFormData` encoding was successful and contains result of the encoding as
+ /// associated values.
+ ///
+ /// - Success: Represents a successful `MultipartFormData` encoding and contains the new `UploadRequest` along with
+ /// streaming information.
+ /// - Failure: Used to represent a failure in the `MultipartFormData` encoding and also contains the encoding
+ /// error.
+ public enum MultipartFormDataEncodingResult {
+ case success(request: UploadRequest, streamingFromDisk: Bool, streamFileURL: URL?)
+ case failure(Error)
+ }
+
+ // MARK: - Properties
+
+ /// A default instance of `SessionManager`, used by top-level Alamofire request methods, and suitable for use
+ /// directly for any ad hoc requests.
+ public static let `default`: SessionManager = {
+ let configuration = URLSessionConfiguration.default
+ configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
+
+ return SessionManager(configuration: configuration)
+ }()
+
+ /// Creates default values for the "Accept-Encoding", "Accept-Language" and "User-Agent" headers.
+ public static let defaultHTTPHeaders: HTTPHeaders = {
+ // Accept-Encoding HTTP Header; see https://tools.ietf.org/html/rfc7230#section-4.2.3
+ let acceptEncoding: String = "gzip;q=1.0, compress;q=0.5"
+
+ // Accept-Language HTTP Header; see https://tools.ietf.org/html/rfc7231#section-5.3.5
+ let acceptLanguage = Locale.preferredLanguages.prefix(6).enumerated().map { index, languageCode in
+ let quality = 1.0 - (Double(index) * 0.1)
+ return "\(languageCode);q=\(quality)"
+ }.joined(separator: ", ")
+
+ // User-Agent Header; see https://tools.ietf.org/html/rfc7231#section-5.5.3
+ // Example: `iOS Example/1.0 (org.alamofire.iOS-Example; build:1; iOS 10.0.0) Alamofire/4.0.0`
+ let userAgent: String = {
+ if let info = Bundle.main.infoDictionary {
+ let executable = info[kCFBundleExecutableKey as String] as? String ?? "Unknown"
+ let bundle = info[kCFBundleIdentifierKey as String] as? String ?? "Unknown"
+ let appVersion = info["CFBundleShortVersionString"] as? String ?? "Unknown"
+ let appBuild = info[kCFBundleVersionKey as String] as? String ?? "Unknown"
+
+ let osNameVersion: String = {
+ let version = ProcessInfo.processInfo.operatingSystemVersion
+ let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)"
+
+ let osName: String = {
+ #if os(iOS)
+ return "iOS"
+ #elseif os(watchOS)
+ return "watchOS"
+ #elseif os(tvOS)
+ return "tvOS"
+ #elseif os(macOS)
+ return "OS X"
+ #elseif os(Linux)
+ return "Linux"
+ #else
+ return "Unknown"
+ #endif
+ }()
+
+ return "\(osName) \(versionString)"
+ }()
+
+ let alamofireVersion: String = {
+ guard
+ let afInfo = Bundle(for: SessionManager.self).infoDictionary,
+ let build = afInfo["CFBundleShortVersionString"]
+ else { return "Unknown" }
+
+ return "Alamofire/\(build)"
+ }()
+
+ return "\(executable)/\(appVersion) (\(bundle); build:\(appBuild); \(osNameVersion)) \(alamofireVersion)"
+ }
+
+ return "Alamofire"
+ }()
+
+ return [
+ "Accept-Encoding": acceptEncoding,
+ "Accept-Language": acceptLanguage,
+ "User-Agent": userAgent
+ ]
+ }()
+
+ /// Default memory threshold used when encoding `MultipartFormData` in bytes.
+ public static let multipartFormDataEncodingMemoryThreshold: UInt64 = 10_000_000
+
+ /// The underlying session.
+ public let session: URLSession
+
+ /// The session delegate handling all the task and session delegate callbacks.
+ public let delegate: SessionDelegate
+
+ /// Whether to start requests immediately after being constructed. `true` by default.
+ open var startRequestsImmediately: Bool = true
+
+ /// The request adapter called each time a new request is created.
+ open var adapter: RequestAdapter?
+
+ /// The request retrier called each time a request encounters an error to determine whether to retry the request.
+ open var retrier: RequestRetrier? {
+ get { return delegate.retrier }
+ set { delegate.retrier = newValue }
+ }
+
+ /// The background completion handler closure provided by the UIApplicationDelegate
+ /// `application:handleEventsForBackgroundURLSession:completionHandler:` method. By setting the background
+ /// completion handler, the SessionDelegate `sessionDidFinishEventsForBackgroundURLSession` closure implementation
+ /// will automatically call the handler.
+ ///
+ /// If you need to handle your own events before the handler is called, then you need to override the
+ /// SessionDelegate `sessionDidFinishEventsForBackgroundURLSession` and manually call the handler when finished.
+ ///
+ /// `nil` by default.
+ open var backgroundCompletionHandler: (() -> Void)?
+
+ let queue = DispatchQueue(label: "org.alamofire.session-manager." + UUID().uuidString)
+
+ // MARK: - Lifecycle
+
+ /// Creates an instance with the specified `configuration`, `delegate` and `serverTrustPolicyManager`.
+ ///
+ /// - parameter configuration: The configuration used to construct the managed session.
+ /// `URLSessionConfiguration.default` by default.
+ /// - parameter delegate: The delegate used when initializing the session. `SessionDelegate()` by
+ /// default.
+ /// - parameter serverTrustPolicyManager: The server trust policy manager to use for evaluating all server trust
+ /// challenges. `nil` by default.
+ ///
+ /// - returns: The new `SessionManager` instance.
+ public init(
+ configuration: URLSessionConfiguration = URLSessionConfiguration.default,
+ delegate: SessionDelegate = SessionDelegate(),
+ serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
+ {
+ self.delegate = delegate
+ self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
+
+ commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
+ }
+
+ /// Creates an instance with the specified `session`, `delegate` and `serverTrustPolicyManager`.
+ ///
+ /// - parameter session: The URL session.
+ /// - parameter delegate: The delegate of the URL session. Must equal the URL session's delegate.
+ /// - parameter serverTrustPolicyManager: The server trust policy manager to use for evaluating all server trust
+ /// challenges. `nil` by default.
+ ///
+ /// - returns: The new `SessionManager` instance if the URL session's delegate matches; `nil` otherwise.
+ public init?(
+ session: URLSession,
+ delegate: SessionDelegate,
+ serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
+ {
+ guard delegate === session.delegate else { return nil }
+
+ self.delegate = delegate
+ self.session = session
+
+ commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
+ }
+
+ private func commonInit(serverTrustPolicyManager: ServerTrustPolicyManager?) {
+ session.serverTrustPolicyManager = serverTrustPolicyManager
+
+ delegate.sessionManager = self
+
+ delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
+ guard let strongSelf = self else { return }
+ DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() }
+ }
+ }
+
+ deinit {
+ session.invalidateAndCancel()
+ }
+
+ // MARK: - Data Request
+
+ /// Creates a `DataRequest` to retrieve the contents of the specified `url`, `method`, `parameters`, `encoding`
+ /// and `headers`.
+ ///
+ /// - parameter url: The URL.
+ /// - parameter method: The HTTP method. `.get` by default.
+ /// - parameter parameters: The parameters. `nil` by default.
+ /// - parameter encoding: The parameter encoding. `URLEncoding.default` by default.
+ /// - parameter headers: The HTTP headers. `nil` by default.
+ ///
+ /// - returns: The created `DataRequest`.
+ @discardableResult
+ open func request(
+ _ url: URLConvertible,
+ method: HTTPMethod = .get,
+ parameters: Parameters? = nil,
+ encoding: ParameterEncoding = URLEncoding.default,
+ headers: HTTPHeaders? = nil)
+ -> DataRequest
+ {
+ var originalRequest: URLRequest?
+
+ do {
+ originalRequest = try URLRequest(url: url, method: method, headers: headers)
+ let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
+ return request(encodedURLRequest)
+ } catch {
+ return request(originalRequest, failedWith: error)
+ }
+ }
+
+ /// Creates a `DataRequest` to retrieve the contents of a URL based on the specified `urlRequest`.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter urlRequest: The URL request.
+ ///
+ /// - returns: The created `DataRequest`.
+ @discardableResult
+ open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
+ var originalRequest: URLRequest?
+
+ do {
+ originalRequest = try urlRequest.asURLRequest()
+ let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
+
+ let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
+ let request = DataRequest(session: session, requestTask: .data(originalTask, task))
+
+ delegate[task] = request
+
+ if startRequestsImmediately { request.resume() }
+
+ return request
+ } catch {
+ return request(originalRequest, failedWith: error)
+ }
+ }
+
+ // MARK: Private - Request Implementation
+
+ private func request(_ urlRequest: URLRequest?, failedWith error: Error) -> DataRequest {
+ var requestTask: Request.RequestTask = .data(nil, nil)
+
+ if let urlRequest = urlRequest {
+ let originalTask = DataRequest.Requestable(urlRequest: urlRequest)
+ requestTask = .data(originalTask, nil)
+ }
+
+ let underlyingError = error.underlyingAdaptError ?? error
+ let request = DataRequest(session: session, requestTask: requestTask, error: underlyingError)
+
+ if let retrier = retrier, error is AdaptError {
+ allowRetrier(retrier, toRetry: request, with: underlyingError)
+ } else {
+ if startRequestsImmediately { request.resume() }
+ }
+
+ return request
+ }
+
+ // MARK: - Download Request
+
+ // MARK: URL Request
+
+ /// Creates a `DownloadRequest` to retrieve the contents the specified `url`, `method`, `parameters`, `encoding`,
+ /// `headers` and save them to the `destination`.
+ ///
+ /// If `destination` is not specified, the contents will remain in the temporary location determined by the
+ /// underlying URL session.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter url: The URL.
+ /// - parameter method: The HTTP method. `.get` by default.
+ /// - parameter parameters: The parameters. `nil` by default.
+ /// - parameter encoding: The parameter encoding. `URLEncoding.default` by default.
+ /// - parameter headers: The HTTP headers. `nil` by default.
+ /// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default.
+ ///
+ /// - returns: The created `DownloadRequest`.
+ @discardableResult
+ open func download(
+ _ url: URLConvertible,
+ method: HTTPMethod = .get,
+ parameters: Parameters? = nil,
+ encoding: ParameterEncoding = URLEncoding.default,
+ headers: HTTPHeaders? = nil,
+ to destination: DownloadRequest.DownloadFileDestination? = nil)
+ -> DownloadRequest
+ {
+ do {
+ let urlRequest = try URLRequest(url: url, method: method, headers: headers)
+ let encodedURLRequest = try encoding.encode(urlRequest, with: parameters)
+ return download(encodedURLRequest, to: destination)
+ } catch {
+ return download(nil, to: destination, failedWith: error)
+ }
+ }
+
+ /// Creates a `DownloadRequest` to retrieve the contents of a URL based on the specified `urlRequest` and save
+ /// them to the `destination`.
+ ///
+ /// If `destination` is not specified, the contents will remain in the temporary location determined by the
+ /// underlying URL session.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter urlRequest: The URL request
+ /// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default.
+ ///
+ /// - returns: The created `DownloadRequest`.
+ @discardableResult
+ open func download(
+ _ urlRequest: URLRequestConvertible,
+ to destination: DownloadRequest.DownloadFileDestination? = nil)
+ -> DownloadRequest
+ {
+ do {
+ let urlRequest = try urlRequest.asURLRequest()
+ return download(.request(urlRequest), to: destination)
+ } catch {
+ return download(nil, to: destination, failedWith: error)
+ }
+ }
+
+ // MARK: Resume Data
+
+ /// Creates a `DownloadRequest` from the `resumeData` produced from a previous request cancellation to retrieve
+ /// the contents of the original request and save them to the `destination`.
+ ///
+ /// If `destination` is not specified, the contents will remain in the temporary location determined by the
+ /// underlying URL session.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// On the latest release of all the Apple platforms (iOS 10, macOS 10.12, tvOS 10, watchOS 3), `resumeData` is broken
+ /// on background URL session configurations. There's an underlying bug in the `resumeData` generation logic where the
+ /// data is written incorrectly and will always fail to resume the download. For more information about the bug and
+ /// possible workarounds, please refer to the following Stack Overflow post:
+ ///
+ /// - http://stackoverflow.com/a/39347461/1342462
+ ///
+ /// - parameter resumeData: The resume data. This is an opaque data blob produced by `URLSessionDownloadTask`
+ /// when a task is cancelled. See `URLSession -downloadTask(withResumeData:)` for
+ /// additional information.
+ /// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default.
+ ///
+ /// - returns: The created `DownloadRequest`.
+ @discardableResult
+ open func download(
+ resumingWith resumeData: Data,
+ to destination: DownloadRequest.DownloadFileDestination? = nil)
+ -> DownloadRequest
+ {
+ return download(.resumeData(resumeData), to: destination)
+ }
+
+ // MARK: Private - Download Implementation
+
+ private func download(
+ _ downloadable: DownloadRequest.Downloadable,
+ to destination: DownloadRequest.DownloadFileDestination?)
+ -> DownloadRequest
+ {
+ do {
+ let task = try downloadable.task(session: session, adapter: adapter, queue: queue)
+ let download = DownloadRequest(session: session, requestTask: .download(downloadable, task))
+
+ download.downloadDelegate.destination = destination
+
+ delegate[task] = download
+
+ if startRequestsImmediately { download.resume() }
+
+ return download
+ } catch {
+ return download(downloadable, to: destination, failedWith: error)
+ }
+ }
+
+ private func download(
+ _ downloadable: DownloadRequest.Downloadable?,
+ to destination: DownloadRequest.DownloadFileDestination?,
+ failedWith error: Error)
+ -> DownloadRequest
+ {
+ var downloadTask: Request.RequestTask = .download(nil, nil)
+
+ if let downloadable = downloadable {
+ downloadTask = .download(downloadable, nil)
+ }
+
+ let underlyingError = error.underlyingAdaptError ?? error
+
+ let download = DownloadRequest(session: session, requestTask: downloadTask, error: underlyingError)
+ download.downloadDelegate.destination = destination
+
+ if let retrier = retrier, error is AdaptError {
+ allowRetrier(retrier, toRetry: download, with: underlyingError)
+ } else {
+ if startRequestsImmediately { download.resume() }
+ }
+
+ return download
+ }
+
+ // MARK: - Upload Request
+
+ // MARK: File
+
+ /// Creates an `UploadRequest` from the specified `url`, `method` and `headers` for uploading the `file`.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter file: The file to upload.
+ /// - parameter url: The URL.
+ /// - parameter method: The HTTP method. `.post` by default.
+ /// - parameter headers: The HTTP headers. `nil` by default.
+ ///
+ /// - returns: The created `UploadRequest`.
+ @discardableResult
+ open func upload(
+ _ fileURL: URL,
+ to url: URLConvertible,
+ method: HTTPMethod = .post,
+ headers: HTTPHeaders? = nil)
+ -> UploadRequest
+ {
+ do {
+ let urlRequest = try URLRequest(url: url, method: method, headers: headers)
+ return upload(fileURL, with: urlRequest)
+ } catch {
+ return upload(nil, failedWith: error)
+ }
+ }
+
+ /// Creates a `UploadRequest` from the specified `urlRequest` for uploading the `file`.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter file: The file to upload.
+ /// - parameter urlRequest: The URL request.
+ ///
+ /// - returns: The created `UploadRequest`.
+ @discardableResult
+ open func upload(_ fileURL: URL, with urlRequest: URLRequestConvertible) -> UploadRequest {
+ do {
+ let urlRequest = try urlRequest.asURLRequest()
+ return upload(.file(fileURL, urlRequest))
+ } catch {
+ return upload(nil, failedWith: error)
+ }
+ }
+
+ // MARK: Data
+
+ /// Creates an `UploadRequest` from the specified `url`, `method` and `headers` for uploading the `data`.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter data: The data to upload.
+ /// - parameter url: The URL.
+ /// - parameter method: The HTTP method. `.post` by default.
+ /// - parameter headers: The HTTP headers. `nil` by default.
+ ///
+ /// - returns: The created `UploadRequest`.
+ @discardableResult
+ open func upload(
+ _ data: Data,
+ to url: URLConvertible,
+ method: HTTPMethod = .post,
+ headers: HTTPHeaders? = nil)
+ -> UploadRequest
+ {
+ do {
+ let urlRequest = try URLRequest(url: url, method: method, headers: headers)
+ return upload(data, with: urlRequest)
+ } catch {
+ return upload(nil, failedWith: error)
+ }
+ }
+
+ /// Creates an `UploadRequest` from the specified `urlRequest` for uploading the `data`.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter data: The data to upload.
+ /// - parameter urlRequest: The URL request.
+ ///
+ /// - returns: The created `UploadRequest`.
+ @discardableResult
+ open func upload(_ data: Data, with urlRequest: URLRequestConvertible) -> UploadRequest {
+ do {
+ let urlRequest = try urlRequest.asURLRequest()
+ return upload(.data(data, urlRequest))
+ } catch {
+ return upload(nil, failedWith: error)
+ }
+ }
+
+ // MARK: InputStream
+
+ /// Creates an `UploadRequest` from the specified `url`, `method` and `headers` for uploading the `stream`.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter stream: The stream to upload.
+ /// - parameter url: The URL.
+ /// - parameter method: The HTTP method. `.post` by default.
+ /// - parameter headers: The HTTP headers. `nil` by default.
+ ///
+ /// - returns: The created `UploadRequest`.
+ @discardableResult
+ open func upload(
+ _ stream: InputStream,
+ to url: URLConvertible,
+ method: HTTPMethod = .post,
+ headers: HTTPHeaders? = nil)
+ -> UploadRequest
+ {
+ do {
+ let urlRequest = try URLRequest(url: url, method: method, headers: headers)
+ return upload(stream, with: urlRequest)
+ } catch {
+ return upload(nil, failedWith: error)
+ }
+ }
+
+ /// Creates an `UploadRequest` from the specified `urlRequest` for uploading the `stream`.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter stream: The stream to upload.
+ /// - parameter urlRequest: The URL request.
+ ///
+ /// - returns: The created `UploadRequest`.
+ @discardableResult
+ open func upload(_ stream: InputStream, with urlRequest: URLRequestConvertible) -> UploadRequest {
+ do {
+ let urlRequest = try urlRequest.asURLRequest()
+ return upload(.stream(stream, urlRequest))
+ } catch {
+ return upload(nil, failedWith: error)
+ }
+ }
+
+ // MARK: MultipartFormData
+
+ /// Encodes `multipartFormData` using `encodingMemoryThreshold` and calls `encodingCompletion` with new
+ /// `UploadRequest` using the `url`, `method` and `headers`.
+ ///
+ /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative
+ /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
+ /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
+ /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
+ /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
+ /// used for larger payloads such as video content.
+ ///
+ /// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
+ /// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
+ /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
+ /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
+ /// technique was used.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
+ /// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes.
+ /// `multipartFormDataEncodingMemoryThreshold` by default.
+ /// - parameter url: The URL.
+ /// - parameter method: The HTTP method. `.post` by default.
+ /// - parameter headers: The HTTP headers. `nil` by default.
+ /// - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
+ open func upload(
+ multipartFormData: @escaping (MultipartFormData) -> Void,
+ usingThreshold encodingMemoryThreshold: UInt64 = SessionManager.multipartFormDataEncodingMemoryThreshold,
+ to url: URLConvertible,
+ method: HTTPMethod = .post,
+ headers: HTTPHeaders? = nil,
+ queue: DispatchQueue? = nil,
+ encodingCompletion: ((MultipartFormDataEncodingResult) -> Void)?)
+ {
+ do {
+ let urlRequest = try URLRequest(url: url, method: method, headers: headers)
+
+ return upload(
+ multipartFormData: multipartFormData,
+ usingThreshold: encodingMemoryThreshold,
+ with: urlRequest,
+ queue: queue,
+ encodingCompletion: encodingCompletion
+ )
+ } catch {
+ (queue ?? DispatchQueue.main).async { encodingCompletion?(.failure(error)) }
+ }
+ }
+
+ /// Encodes `multipartFormData` using `encodingMemoryThreshold` and calls `encodingCompletion` with new
+ /// `UploadRequest` using the `urlRequest`.
+ ///
+ /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative
+ /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most
+ /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to
+ /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory
+ /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be
+ /// used for larger payloads such as video content.
+ ///
+ /// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory
+ /// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`,
+ /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk
+ /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding
+ /// technique was used.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`.
+ /// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes.
+ /// `multipartFormDataEncodingMemoryThreshold` by default.
+ /// - parameter urlRequest: The URL request.
+ /// - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete.
+ open func upload(
+ multipartFormData: @escaping (MultipartFormData) -> Void,
+ usingThreshold encodingMemoryThreshold: UInt64 = SessionManager.multipartFormDataEncodingMemoryThreshold,
+ with urlRequest: URLRequestConvertible,
+ queue: DispatchQueue? = nil,
+ encodingCompletion: ((MultipartFormDataEncodingResult) -> Void)?)
+ {
+ DispatchQueue.global(qos: .utility).async {
+ let formData = MultipartFormData()
+ multipartFormData(formData)
+
+ var tempFileURL: URL?
+
+ do {
+ var urlRequestWithContentType = try urlRequest.asURLRequest()
+ urlRequestWithContentType.setValue(formData.contentType, forHTTPHeaderField: "Content-Type")
+
+ let isBackgroundSession = self.session.configuration.identifier != nil
+
+ if formData.contentLength < encodingMemoryThreshold && !isBackgroundSession {
+ let data = try formData.encode()
+
+ let encodingResult = MultipartFormDataEncodingResult.success(
+ request: self.upload(data, with: urlRequestWithContentType),
+ streamingFromDisk: false,
+ streamFileURL: nil
+ )
+
+ (queue ?? DispatchQueue.main).async { encodingCompletion?(encodingResult) }
+ } else {
+ let fileManager = FileManager.default
+ let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory())
+ let directoryURL = tempDirectoryURL.appendingPathComponent("org.alamofire.manager/multipart.form.data")
+ let fileName = UUID().uuidString
+ let fileURL = directoryURL.appendingPathComponent(fileName)
+
+ tempFileURL = fileURL
+
+ var directoryError: Error?
+
+ // Create directory inside serial queue to ensure two threads don't do this in parallel
+ self.queue.sync {
+ do {
+ try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
+ } catch {
+ directoryError = error
+ }
+ }
+
+ if let directoryError = directoryError { throw directoryError }
+
+ try formData.writeEncodedData(to: fileURL)
+
+ let upload = self.upload(fileURL, with: urlRequestWithContentType)
+
+ // Cleanup the temp file once the upload is complete
+ upload.delegate.queue.addOperation {
+ do {
+ try FileManager.default.removeItem(at: fileURL)
+ } catch {
+ // No-op
+ }
+ }
+
+ (queue ?? DispatchQueue.main).async {
+ let encodingResult = MultipartFormDataEncodingResult.success(
+ request: upload,
+ streamingFromDisk: true,
+ streamFileURL: fileURL
+ )
+
+ encodingCompletion?(encodingResult)
+ }
+ }
+ } catch {
+ // Cleanup the temp file in the event that the multipart form data encoding failed
+ if let tempFileURL = tempFileURL {
+ do {
+ try FileManager.default.removeItem(at: tempFileURL)
+ } catch {
+ // No-op
+ }
+ }
+
+ (queue ?? DispatchQueue.main).async { encodingCompletion?(.failure(error)) }
+ }
+ }
+ }
+
+ // MARK: Private - Upload Implementation
+
+ private func upload(_ uploadable: UploadRequest.Uploadable) -> UploadRequest {
+ do {
+ let task = try uploadable.task(session: session, adapter: adapter, queue: queue)
+ let upload = UploadRequest(session: session, requestTask: .upload(uploadable, task))
+
+ if case let .stream(inputStream, _) = uploadable {
+ upload.delegate.taskNeedNewBodyStream = { _, _ in inputStream }
+ }
+
+ delegate[task] = upload
+
+ if startRequestsImmediately { upload.resume() }
+
+ return upload
+ } catch {
+ return upload(uploadable, failedWith: error)
+ }
+ }
+
+ private func upload(_ uploadable: UploadRequest.Uploadable?, failedWith error: Error) -> UploadRequest {
+ var uploadTask: Request.RequestTask = .upload(nil, nil)
+
+ if let uploadable = uploadable {
+ uploadTask = .upload(uploadable, nil)
+ }
+
+ let underlyingError = error.underlyingAdaptError ?? error
+ let upload = UploadRequest(session: session, requestTask: uploadTask, error: underlyingError)
+
+ if let retrier = retrier, error is AdaptError {
+ allowRetrier(retrier, toRetry: upload, with: underlyingError)
+ } else {
+ if startRequestsImmediately { upload.resume() }
+ }
+
+ return upload
+ }
+
+#if !os(watchOS)
+
+ // MARK: - Stream Request
+
+ // MARK: Hostname and Port
+
+ /// Creates a `StreamRequest` for bidirectional streaming using the `hostname` and `port`.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter hostName: The hostname of the server to connect to.
+ /// - parameter port: The port of the server to connect to.
+ ///
+ /// - returns: The created `StreamRequest`.
+ @discardableResult
+ @available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+ open func stream(withHostName hostName: String, port: Int) -> StreamRequest {
+ return stream(.stream(hostName: hostName, port: port))
+ }
+
+ // MARK: NetService
+
+ /// Creates a `StreamRequest` for bidirectional streaming using the `netService`.
+ ///
+ /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned.
+ ///
+ /// - parameter netService: The net service used to identify the endpoint.
+ ///
+ /// - returns: The created `StreamRequest`.
+ @discardableResult
+ @available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+ open func stream(with netService: NetService) -> StreamRequest {
+ return stream(.netService(netService))
+ }
+
+ // MARK: Private - Stream Implementation
+
+ @available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+ private func stream(_ streamable: StreamRequest.Streamable) -> StreamRequest {
+ do {
+ let task = try streamable.task(session: session, adapter: adapter, queue: queue)
+ let request = StreamRequest(session: session, requestTask: .stream(streamable, task))
+
+ delegate[task] = request
+
+ if startRequestsImmediately { request.resume() }
+
+ return request
+ } catch {
+ return stream(failedWith: error)
+ }
+ }
+
+ @available(iOS 9.0, macOS 10.11, tvOS 9.0, *)
+ private func stream(failedWith error: Error) -> StreamRequest {
+ let stream = StreamRequest(session: session, requestTask: .stream(nil, nil), error: error)
+ if startRequestsImmediately { stream.resume() }
+ return stream
+ }
+
+#endif
+
+ // MARK: - Internal - Retry Request
+
+ func retry(_ request: Request) -> Bool {
+ guard let originalTask = request.originalTask else { return false }
+
+ do {
+ let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
+
+ if let originalTask = request.task {
+ delegate[originalTask] = nil // removes the old request to avoid endless growth
+ }
+
+ request.delegate.task = task // resets all task delegate data
+
+ request.retryCount += 1
+ request.startTime = CFAbsoluteTimeGetCurrent()
+ request.endTime = nil
+
+ task.resume()
+
+ return true
+ } catch {
+ request.delegate.error = error.underlyingAdaptError ?? error
+ return false
+ }
+ }
+
+ private func allowRetrier(_ retrier: RequestRetrier, toRetry request: Request, with error: Error) {
+ DispatchQueue.utility.async { [weak self] in
+ guard let strongSelf = self else { return }
+
+ retrier.should(strongSelf, retry: request, with: error) { shouldRetry, timeDelay in
+ guard let strongSelf = self else { return }
+
+ guard shouldRetry else {
+ if strongSelf.startRequestsImmediately { request.resume() }
+ return
+ }
+
+ DispatchQueue.utility.after(timeDelay) {
+ guard let strongSelf = self else { return }
+
+ let retrySucceeded = strongSelf.retry(request)
+
+ if retrySucceeded, let task = request.task {
+ strongSelf.delegate[task] = request
+ } else {
+ if strongSelf.startRequestsImmediately { request.resume() }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Pods/Alamofire/Source/TaskDelegate.swift b/Pods/Alamofire/Source/TaskDelegate.swift
new file mode 100644
index 0000000..5705737
--- /dev/null
+++ b/Pods/Alamofire/Source/TaskDelegate.swift
@@ -0,0 +1,466 @@
+//
+// TaskDelegate.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// The task delegate is responsible for handling all delegate callbacks for the underlying task as well as
+/// executing all operations attached to the serial operation queue upon task completion.
+open class TaskDelegate: NSObject {
+
+ // MARK: Properties
+
+ /// The serial operation queue used to execute all operations after the task completes.
+ public let queue: OperationQueue
+
+ /// The data returned by the server.
+ public var data: Data? { return nil }
+
+ /// The error generated throughout the lifecyle of the task.
+ public var error: Error?
+
+ var task: URLSessionTask? {
+ set {
+ taskLock.lock(); defer { taskLock.unlock() }
+ _task = newValue
+ }
+ get {
+ taskLock.lock(); defer { taskLock.unlock() }
+ return _task
+ }
+ }
+
+ var initialResponseTime: CFAbsoluteTime?
+ var credential: URLCredential?
+ var metrics: AnyObject? // URLSessionTaskMetrics
+
+ private var _task: URLSessionTask? {
+ didSet { reset() }
+ }
+
+ private let taskLock = NSLock()
+
+ // MARK: Lifecycle
+
+ init(task: URLSessionTask?) {
+ _task = task
+
+ self.queue = {
+ let operationQueue = OperationQueue()
+
+ operationQueue.maxConcurrentOperationCount = 1
+ operationQueue.isSuspended = true
+ operationQueue.qualityOfService = .utility
+
+ return operationQueue
+ }()
+ }
+
+ func reset() {
+ error = nil
+ initialResponseTime = nil
+ }
+
+ // MARK: URLSessionTaskDelegate
+
+ var taskWillPerformHTTPRedirection: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest) -> URLRequest?)?
+ var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?
+ var taskNeedNewBodyStream: ((URLSession, URLSessionTask) -> InputStream?)?
+ var taskDidCompleteWithError: ((URLSession, URLSessionTask, Error?) -> Void)?
+
+ @objc(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)
+ func urlSession(
+ _ session: URLSession,
+ task: URLSessionTask,
+ willPerformHTTPRedirection response: HTTPURLResponse,
+ newRequest request: URLRequest,
+ completionHandler: @escaping (URLRequest?) -> Void)
+ {
+ var redirectRequest: URLRequest? = request
+
+ if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection {
+ redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request)
+ }
+
+ completionHandler(redirectRequest)
+ }
+
+ @objc(URLSession:task:didReceiveChallenge:completionHandler:)
+ func urlSession(
+ _ session: URLSession,
+ task: URLSessionTask,
+ didReceive challenge: URLAuthenticationChallenge,
+ completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
+ {
+ var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
+ var credential: URLCredential?
+
+ if let taskDidReceiveChallenge = taskDidReceiveChallenge {
+ (disposition, credential) = taskDidReceiveChallenge(session, task, challenge)
+ } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
+ let host = challenge.protectionSpace.host
+
+ if
+ let serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicy(forHost: host),
+ let serverTrust = challenge.protectionSpace.serverTrust
+ {
+ if serverTrustPolicy.evaluate(serverTrust, forHost: host) {
+ disposition = .useCredential
+ credential = URLCredential(trust: serverTrust)
+ } else {
+ disposition = .cancelAuthenticationChallenge
+ }
+ }
+ } else {
+ if challenge.previousFailureCount > 0 {
+ disposition = .rejectProtectionSpace
+ } else {
+ credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace)
+
+ if credential != nil {
+ disposition = .useCredential
+ }
+ }
+ }
+
+ completionHandler(disposition, credential)
+ }
+
+ @objc(URLSession:task:needNewBodyStream:)
+ func urlSession(
+ _ session: URLSession,
+ task: URLSessionTask,
+ needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)
+ {
+ var bodyStream: InputStream?
+
+ if let taskNeedNewBodyStream = taskNeedNewBodyStream {
+ bodyStream = taskNeedNewBodyStream(session, task)
+ }
+
+ completionHandler(bodyStream)
+ }
+
+ @objc(URLSession:task:didCompleteWithError:)
+ func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
+ if let taskDidCompleteWithError = taskDidCompleteWithError {
+ taskDidCompleteWithError(session, task, error)
+ } else {
+ if let error = error {
+ if self.error == nil { self.error = error }
+
+ if
+ let downloadDelegate = self as? DownloadTaskDelegate,
+ let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data
+ {
+ downloadDelegate.resumeData = resumeData
+ }
+ }
+
+ queue.isSuspended = false
+ }
+ }
+}
+
+// MARK: -
+
+class DataTaskDelegate: TaskDelegate, URLSessionDataDelegate {
+
+ // MARK: Properties
+
+ var dataTask: URLSessionDataTask { return task as! URLSessionDataTask }
+
+ override var data: Data? {
+ if dataStream != nil {
+ return nil
+ } else {
+ return mutableData
+ }
+ }
+
+ var progress: Progress
+ var progressHandler: (closure: Request.ProgressHandler, queue: DispatchQueue)?
+
+ var dataStream: ((_ data: Data) -> Void)?
+
+ private var totalBytesReceived: Int64 = 0
+ private var mutableData: Data
+
+ private var expectedContentLength: Int64?
+
+ // MARK: Lifecycle
+
+ override init(task: URLSessionTask?) {
+ mutableData = Data()
+ progress = Progress(totalUnitCount: 0)
+
+ super.init(task: task)
+ }
+
+ override func reset() {
+ super.reset()
+
+ progress = Progress(totalUnitCount: 0)
+ totalBytesReceived = 0
+ mutableData = Data()
+ expectedContentLength = nil
+ }
+
+ // MARK: URLSessionDataDelegate
+
+ var dataTaskDidReceiveResponse: ((URLSession, URLSessionDataTask, URLResponse) -> URLSession.ResponseDisposition)?
+ var dataTaskDidBecomeDownloadTask: ((URLSession, URLSessionDataTask, URLSessionDownloadTask) -> Void)?
+ var dataTaskDidReceiveData: ((URLSession, URLSessionDataTask, Data) -> Void)?
+ var dataTaskWillCacheResponse: ((URLSession, URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)?
+
+ func urlSession(
+ _ session: URLSession,
+ dataTask: URLSessionDataTask,
+ didReceive response: URLResponse,
+ completionHandler: @escaping (URLSession.ResponseDisposition) -> Void)
+ {
+ var disposition: URLSession.ResponseDisposition = .allow
+
+ expectedContentLength = response.expectedContentLength
+
+ if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse {
+ disposition = dataTaskDidReceiveResponse(session, dataTask, response)
+ }
+
+ completionHandler(disposition)
+ }
+
+ func urlSession(
+ _ session: URLSession,
+ dataTask: URLSessionDataTask,
+ didBecome downloadTask: URLSessionDownloadTask)
+ {
+ dataTaskDidBecomeDownloadTask?(session, dataTask, downloadTask)
+ }
+
+ func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
+ if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
+
+ if let dataTaskDidReceiveData = dataTaskDidReceiveData {
+ dataTaskDidReceiveData(session, dataTask, data)
+ } else {
+ if let dataStream = dataStream {
+ dataStream(data)
+ } else {
+ mutableData.append(data)
+ }
+
+ let bytesReceived = Int64(data.count)
+ totalBytesReceived += bytesReceived
+ let totalBytesExpected = dataTask.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
+
+ progress.totalUnitCount = totalBytesExpected
+ progress.completedUnitCount = totalBytesReceived
+
+ if let progressHandler = progressHandler {
+ progressHandler.queue.async { progressHandler.closure(self.progress) }
+ }
+ }
+ }
+
+ func urlSession(
+ _ session: URLSession,
+ dataTask: URLSessionDataTask,
+ willCacheResponse proposedResponse: CachedURLResponse,
+ completionHandler: @escaping (CachedURLResponse?) -> Void)
+ {
+ var cachedResponse: CachedURLResponse? = proposedResponse
+
+ if let dataTaskWillCacheResponse = dataTaskWillCacheResponse {
+ cachedResponse = dataTaskWillCacheResponse(session, dataTask, proposedResponse)
+ }
+
+ completionHandler(cachedResponse)
+ }
+}
+
+// MARK: -
+
+class DownloadTaskDelegate: TaskDelegate, URLSessionDownloadDelegate {
+
+ // MARK: Properties
+
+ var downloadTask: URLSessionDownloadTask { return task as! URLSessionDownloadTask }
+
+ var progress: Progress
+ var progressHandler: (closure: Request.ProgressHandler, queue: DispatchQueue)?
+
+ var resumeData: Data?
+ override var data: Data? { return resumeData }
+
+ var destination: DownloadRequest.DownloadFileDestination?
+
+ var temporaryURL: URL?
+ var destinationURL: URL?
+
+ var fileURL: URL? { return destination != nil ? destinationURL : temporaryURL }
+
+ // MARK: Lifecycle
+
+ override init(task: URLSessionTask?) {
+ progress = Progress(totalUnitCount: 0)
+ super.init(task: task)
+ }
+
+ override func reset() {
+ super.reset()
+
+ progress = Progress(totalUnitCount: 0)
+ resumeData = nil
+ }
+
+ // MARK: URLSessionDownloadDelegate
+
+ var downloadTaskDidFinishDownloadingToURL: ((URLSession, URLSessionDownloadTask, URL) -> URL)?
+ var downloadTaskDidWriteData: ((URLSession, URLSessionDownloadTask, Int64, Int64, Int64) -> Void)?
+ var downloadTaskDidResumeAtOffset: ((URLSession, URLSessionDownloadTask, Int64, Int64) -> Void)?
+
+ func urlSession(
+ _ session: URLSession,
+ downloadTask: URLSessionDownloadTask,
+ didFinishDownloadingTo location: URL)
+ {
+ temporaryURL = location
+
+ guard
+ let destination = destination,
+ let response = downloadTask.response as? HTTPURLResponse
+ else { return }
+
+ let result = destination(location, response)
+ let destinationURL = result.destinationURL
+ let options = result.options
+
+ self.destinationURL = destinationURL
+
+ do {
+ if options.contains(.removePreviousFile), FileManager.default.fileExists(atPath: destinationURL.path) {
+ try FileManager.default.removeItem(at: destinationURL)
+ }
+
+ if options.contains(.createIntermediateDirectories) {
+ let directory = destinationURL.deletingLastPathComponent()
+ try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
+ }
+
+ try FileManager.default.moveItem(at: location, to: destinationURL)
+ } catch {
+ self.error = error
+ }
+ }
+
+ func urlSession(
+ _ session: URLSession,
+ downloadTask: URLSessionDownloadTask,
+ didWriteData bytesWritten: Int64,
+ totalBytesWritten: Int64,
+ totalBytesExpectedToWrite: Int64)
+ {
+ if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
+
+ if let downloadTaskDidWriteData = downloadTaskDidWriteData {
+ downloadTaskDidWriteData(
+ session,
+ downloadTask,
+ bytesWritten,
+ totalBytesWritten,
+ totalBytesExpectedToWrite
+ )
+ } else {
+ progress.totalUnitCount = totalBytesExpectedToWrite
+ progress.completedUnitCount = totalBytesWritten
+
+ if let progressHandler = progressHandler {
+ progressHandler.queue.async { progressHandler.closure(self.progress) }
+ }
+ }
+ }
+
+ func urlSession(
+ _ session: URLSession,
+ downloadTask: URLSessionDownloadTask,
+ didResumeAtOffset fileOffset: Int64,
+ expectedTotalBytes: Int64)
+ {
+ if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset {
+ downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes)
+ } else {
+ progress.totalUnitCount = expectedTotalBytes
+ progress.completedUnitCount = fileOffset
+ }
+ }
+}
+
+// MARK: -
+
+class UploadTaskDelegate: DataTaskDelegate {
+
+ // MARK: Properties
+
+ var uploadTask: URLSessionUploadTask { return task as! URLSessionUploadTask }
+
+ var uploadProgress: Progress
+ var uploadProgressHandler: (closure: Request.ProgressHandler, queue: DispatchQueue)?
+
+ // MARK: Lifecycle
+
+ override init(task: URLSessionTask?) {
+ uploadProgress = Progress(totalUnitCount: 0)
+ super.init(task: task)
+ }
+
+ override func reset() {
+ super.reset()
+ uploadProgress = Progress(totalUnitCount: 0)
+ }
+
+ // MARK: URLSessionTaskDelegate
+
+ var taskDidSendBodyData: ((URLSession, URLSessionTask, Int64, Int64, Int64) -> Void)?
+
+ func URLSession(
+ _ session: URLSession,
+ task: URLSessionTask,
+ didSendBodyData bytesSent: Int64,
+ totalBytesSent: Int64,
+ totalBytesExpectedToSend: Int64)
+ {
+ if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
+
+ if let taskDidSendBodyData = taskDidSendBodyData {
+ taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend)
+ } else {
+ uploadProgress.totalUnitCount = totalBytesExpectedToSend
+ uploadProgress.completedUnitCount = totalBytesSent
+
+ if let uploadProgressHandler = uploadProgressHandler {
+ uploadProgressHandler.queue.async { uploadProgressHandler.closure(self.uploadProgress) }
+ }
+ }
+ }
+}
diff --git a/Pods/Alamofire/Source/Timeline.swift b/Pods/Alamofire/Source/Timeline.swift
new file mode 100644
index 0000000..596c1bd
--- /dev/null
+++ b/Pods/Alamofire/Source/Timeline.swift
@@ -0,0 +1,136 @@
+//
+// Timeline.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+/// Responsible for computing the timing metrics for the complete lifecycle of a `Request`.
+public struct Timeline {
+ /// The time the request was initialized.
+ public let requestStartTime: CFAbsoluteTime
+
+ /// The time the first bytes were received from or sent to the server.
+ public let initialResponseTime: CFAbsoluteTime
+
+ /// The time when the request was completed.
+ public let requestCompletedTime: CFAbsoluteTime
+
+ /// The time when the response serialization was completed.
+ public let serializationCompletedTime: CFAbsoluteTime
+
+ /// The time interval in seconds from the time the request started to the initial response from the server.
+ public let latency: TimeInterval
+
+ /// The time interval in seconds from the time the request started to the time the request completed.
+ public let requestDuration: TimeInterval
+
+ /// The time interval in seconds from the time the request completed to the time response serialization completed.
+ public let serializationDuration: TimeInterval
+
+ /// The time interval in seconds from the time the request started to the time response serialization completed.
+ public let totalDuration: TimeInterval
+
+ /// Creates a new `Timeline` instance with the specified request times.
+ ///
+ /// - parameter requestStartTime: The time the request was initialized. Defaults to `0.0`.
+ /// - parameter initialResponseTime: The time the first bytes were received from or sent to the server.
+ /// Defaults to `0.0`.
+ /// - parameter requestCompletedTime: The time when the request was completed. Defaults to `0.0`.
+ /// - parameter serializationCompletedTime: The time when the response serialization was completed. Defaults
+ /// to `0.0`.
+ ///
+ /// - returns: The new `Timeline` instance.
+ public init(
+ requestStartTime: CFAbsoluteTime = 0.0,
+ initialResponseTime: CFAbsoluteTime = 0.0,
+ requestCompletedTime: CFAbsoluteTime = 0.0,
+ serializationCompletedTime: CFAbsoluteTime = 0.0)
+ {
+ self.requestStartTime = requestStartTime
+ self.initialResponseTime = initialResponseTime
+ self.requestCompletedTime = requestCompletedTime
+ self.serializationCompletedTime = serializationCompletedTime
+
+ self.latency = initialResponseTime - requestStartTime
+ self.requestDuration = requestCompletedTime - requestStartTime
+ self.serializationDuration = serializationCompletedTime - requestCompletedTime
+ self.totalDuration = serializationCompletedTime - requestStartTime
+ }
+}
+
+// MARK: - CustomStringConvertible
+
+extension Timeline: CustomStringConvertible {
+ /// The textual representation used when written to an output stream, which includes the latency, the request
+ /// duration and the total duration.
+ public var description: String {
+ let latency = String(format: "%.3f", self.latency)
+ let requestDuration = String(format: "%.3f", self.requestDuration)
+ let serializationDuration = String(format: "%.3f", self.serializationDuration)
+ let totalDuration = String(format: "%.3f", self.totalDuration)
+
+ // NOTE: Had to move to string concatenation due to memory leak filed as rdar://26761490. Once memory leak is
+ // fixed, we should move back to string interpolation by reverting commit 7d4a43b1.
+ let timings = [
+ "\"Latency\": " + latency + " secs",
+ "\"Request Duration\": " + requestDuration + " secs",
+ "\"Serialization Duration\": " + serializationDuration + " secs",
+ "\"Total Duration\": " + totalDuration + " secs"
+ ]
+
+ return "Timeline: { " + timings.joined(separator: ", ") + " }"
+ }
+}
+
+// MARK: - CustomDebugStringConvertible
+
+extension Timeline: CustomDebugStringConvertible {
+ /// The textual representation used when written to an output stream, which includes the request start time, the
+ /// initial response time, the request completed time, the serialization completed time, the latency, the request
+ /// duration and the total duration.
+ public var debugDescription: String {
+ let requestStartTime = String(format: "%.3f", self.requestStartTime)
+ let initialResponseTime = String(format: "%.3f", self.initialResponseTime)
+ let requestCompletedTime = String(format: "%.3f", self.requestCompletedTime)
+ let serializationCompletedTime = String(format: "%.3f", self.serializationCompletedTime)
+ let latency = String(format: "%.3f", self.latency)
+ let requestDuration = String(format: "%.3f", self.requestDuration)
+ let serializationDuration = String(format: "%.3f", self.serializationDuration)
+ let totalDuration = String(format: "%.3f", self.totalDuration)
+
+ // NOTE: Had to move to string concatenation due to memory leak filed as rdar://26761490. Once memory leak is
+ // fixed, we should move back to string interpolation by reverting commit 7d4a43b1.
+ let timings = [
+ "\"Request Start Time\": " + requestStartTime,
+ "\"Initial Response Time\": " + initialResponseTime,
+ "\"Request Completed Time\": " + requestCompletedTime,
+ "\"Serialization Completed Time\": " + serializationCompletedTime,
+ "\"Latency\": " + latency + " secs",
+ "\"Request Duration\": " + requestDuration + " secs",
+ "\"Serialization Duration\": " + serializationDuration + " secs",
+ "\"Total Duration\": " + totalDuration + " secs"
+ ]
+
+ return "Timeline: { " + timings.joined(separator: ", ") + " }"
+ }
+}
diff --git a/Pods/Alamofire/Source/Validation.swift b/Pods/Alamofire/Source/Validation.swift
new file mode 100644
index 0000000..59e0bbb
--- /dev/null
+++ b/Pods/Alamofire/Source/Validation.swift
@@ -0,0 +1,321 @@
+//
+// Validation.swift
+//
+// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+import Foundation
+
+extension Request {
+
+ // MARK: Helper Types
+
+ fileprivate typealias ErrorReason = AFError.ResponseValidationFailureReason
+
+ /// Used to represent whether validation was successful or encountered an error resulting in a failure.
+ ///
+ /// - success: The validation was successful.
+ /// - failure: The validation failed encountering the provided error.
+ public enum ValidationResult {
+ case success
+ case failure(Error)
+ }
+
+ fileprivate struct MIMEType {
+ let type: String
+ let subtype: String
+
+ var isWildcard: Bool { return type == "*" && subtype == "*" }
+
+ init?(_ string: String) {
+ let components: [String] = {
+ let stripped = string.trimmingCharacters(in: .whitespacesAndNewlines)
+
+ #if swift(>=3.2)
+ let split = stripped[..<(stripped.range(of: ";")?.lowerBound ?? stripped.endIndex)]
+ #else
+ let split = stripped.substring(to: stripped.range(of: ";")?.lowerBound ?? stripped.endIndex)
+ #endif
+
+ return split.components(separatedBy: "/")
+ }()
+
+ if let type = components.first, let subtype = components.last {
+ self.type = type
+ self.subtype = subtype
+ } else {
+ return nil
+ }
+ }
+
+ func matches(_ mime: MIMEType) -> Bool {
+ switch (type, subtype) {
+ case (mime.type, mime.subtype), (mime.type, "*"), ("*", mime.subtype), ("*", "*"):
+ return true
+ default:
+ return false
+ }
+ }
+ }
+
+ // MARK: Properties
+
+ fileprivate var acceptableStatusCodes: [Int] { return Array(200..<300) }
+
+ fileprivate var acceptableContentTypes: [String] {
+ if let accept = request?.value(forHTTPHeaderField: "Accept") {
+ return accept.components(separatedBy: ",")
+ }
+
+ return ["*/*"]
+ }
+
+ // MARK: Status Code
+
+ fileprivate func validate(
+ statusCode acceptableStatusCodes: S,
+ response: HTTPURLResponse)
+ -> ValidationResult
+ where S.Iterator.Element == Int
+ {
+ if acceptableStatusCodes.contains(response.statusCode) {
+ return .success
+ } else {
+ let reason: ErrorReason = .unacceptableStatusCode(code: response.statusCode)
+ return .failure(AFError.responseValidationFailed(reason: reason))
+ }
+ }
+
+ // MARK: Content Type
+
+ fileprivate func validate(
+ contentType acceptableContentTypes: S,
+ response: HTTPURLResponse,
+ data: Data?)
+ -> ValidationResult
+ where S.Iterator.Element == String
+ {
+ guard let data = data, data.count > 0 else { return .success }
+
+ guard
+ let responseContentType = response.mimeType,
+ let responseMIMEType = MIMEType(responseContentType)
+ else {
+ for contentType in acceptableContentTypes {
+ if let mimeType = MIMEType(contentType), mimeType.isWildcard {
+ return .success
+ }
+ }
+
+ let error: AFError = {
+ let reason: ErrorReason = .missingContentType(acceptableContentTypes: Array(acceptableContentTypes))
+ return AFError.responseValidationFailed(reason: reason)
+ }()
+
+ return .failure(error)
+ }
+
+ for contentType in acceptableContentTypes {
+ if let acceptableMIMEType = MIMEType(contentType), acceptableMIMEType.matches(responseMIMEType) {
+ return .success
+ }
+ }
+
+ let error: AFError = {
+ let reason: ErrorReason = .unacceptableContentType(
+ acceptableContentTypes: Array(acceptableContentTypes),
+ responseContentType: responseContentType
+ )
+
+ return AFError.responseValidationFailed(reason: reason)
+ }()
+
+ return .failure(error)
+ }
+}
+
+// MARK: -
+
+extension DataRequest {
+ /// A closure used to validate a request that takes a URL request, a URL response and data, and returns whether the
+ /// request was valid.
+ public typealias Validation = (URLRequest?, HTTPURLResponse, Data?) -> ValidationResult
+
+ /// Validates the request, using the specified closure.
+ ///
+ /// If validation fails, subsequent calls to response handlers will have an associated error.
+ ///
+ /// - parameter validation: A closure to validate the request.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func validate(_ validation: @escaping Validation) -> Self {
+ let validationExecution: () -> Void = { [unowned self] in
+ if
+ let response = self.response,
+ self.delegate.error == nil,
+ case let .failure(error) = validation(self.request, response, self.delegate.data)
+ {
+ self.delegate.error = error
+ }
+ }
+
+ validations.append(validationExecution)
+
+ return self
+ }
+
+ /// Validates that the response has a status code in the specified sequence.
+ ///
+ /// If validation fails, subsequent calls to response handlers will have an associated error.
+ ///
+ /// - parameter range: The range of acceptable status codes.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int {
+ return validate { [unowned self] _, response, _ in
+ return self.validate(statusCode: acceptableStatusCodes, response: response)
+ }
+ }
+
+ /// Validates that the response has a content type in the specified sequence.
+ ///
+ /// If validation fails, subsequent calls to response handlers will have an associated error.
+ ///
+ /// - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func validate(contentType acceptableContentTypes: S) -> Self where S.Iterator.Element == String {
+ return validate { [unowned self] _, response, data in
+ return self.validate(contentType: acceptableContentTypes, response: response, data: data)
+ }
+ }
+
+ /// Validates that the response has a status code in the default acceptable range of 200...299, and that the content
+ /// type matches any specified in the Accept HTTP header field.
+ ///
+ /// If validation fails, subsequent calls to response handlers will have an associated error.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func validate() -> Self {
+ let contentTypes = { [unowned self] in
+ self.acceptableContentTypes
+ }
+ return validate(statusCode: acceptableStatusCodes).validate(contentType: contentTypes())
+ }
+}
+
+// MARK: -
+
+extension DownloadRequest {
+ /// A closure used to validate a request that takes a URL request, a URL response, a temporary URL and a
+ /// destination URL, and returns whether the request was valid.
+ public typealias Validation = (
+ _ request: URLRequest?,
+ _ response: HTTPURLResponse,
+ _ temporaryURL: URL?,
+ _ destinationURL: URL?)
+ -> ValidationResult
+
+ /// Validates the request, using the specified closure.
+ ///
+ /// If validation fails, subsequent calls to response handlers will have an associated error.
+ ///
+ /// - parameter validation: A closure to validate the request.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func validate(_ validation: @escaping Validation) -> Self {
+ let validationExecution: () -> Void = { [unowned self] in
+ let request = self.request
+ let temporaryURL = self.downloadDelegate.temporaryURL
+ let destinationURL = self.downloadDelegate.destinationURL
+
+ if
+ let response = self.response,
+ self.delegate.error == nil,
+ case let .failure(error) = validation(request, response, temporaryURL, destinationURL)
+ {
+ self.delegate.error = error
+ }
+ }
+
+ validations.append(validationExecution)
+
+ return self
+ }
+
+ /// Validates that the response has a status code in the specified sequence.
+ ///
+ /// If validation fails, subsequent calls to response handlers will have an associated error.
+ ///
+ /// - parameter range: The range of acceptable status codes.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int {
+ return validate { [unowned self] _, response, _, _ in
+ return self.validate(statusCode: acceptableStatusCodes, response: response)
+ }
+ }
+
+ /// Validates that the response has a content type in the specified sequence.
+ ///
+ /// If validation fails, subsequent calls to response handlers will have an associated error.
+ ///
+ /// - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func validate(contentType acceptableContentTypes: S) -> Self where S.Iterator.Element == String {
+ return validate { [unowned self] _, response, _, _ in
+ let fileURL = self.downloadDelegate.fileURL
+
+ guard let validFileURL = fileURL else {
+ return .failure(AFError.responseValidationFailed(reason: .dataFileNil))
+ }
+
+ do {
+ let data = try Data(contentsOf: validFileURL)
+ return self.validate(contentType: acceptableContentTypes, response: response, data: data)
+ } catch {
+ return .failure(AFError.responseValidationFailed(reason: .dataFileReadFailed(at: validFileURL)))
+ }
+ }
+ }
+
+ /// Validates that the response has a status code in the default acceptable range of 200...299, and that the content
+ /// type matches any specified in the Accept HTTP header field.
+ ///
+ /// If validation fails, subsequent calls to response handlers will have an associated error.
+ ///
+ /// - returns: The request.
+ @discardableResult
+ public func validate() -> Self {
+ let contentTypes = { [unowned self] in
+ self.acceptableContentTypes
+ }
+ return validate(statusCode: acceptableStatusCodes).validate(contentType: contentTypes())
+ }
+}
diff --git a/Pods/AlamofireObjectMapper/AlamofireObjectMapper/AlamofireObjectMapper.swift b/Pods/AlamofireObjectMapper/AlamofireObjectMapper/AlamofireObjectMapper.swift
new file mode 100644
index 0000000..b181e84
--- /dev/null
+++ b/Pods/AlamofireObjectMapper/AlamofireObjectMapper/AlamofireObjectMapper.swift
@@ -0,0 +1,205 @@
+//
+// Request.swift
+// AlamofireObjectMapper
+//
+// Created by Tristan Himmelman on 2015-04-30.
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2014-2015 Tristan Himmelman
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+import Alamofire
+import ObjectMapper
+
+extension DataRequest {
+
+ enum ErrorCode: Int {
+ case noData = 1
+ case dataSerializationFailed = 2
+ }
+
+ internal static func newError(_ code: ErrorCode, failureReason: String) -> NSError {
+ let errorDomain = "com.alamofireobjectmapper.error"
+
+ let userInfo = [NSLocalizedFailureReasonErrorKey: failureReason]
+ let returnError = NSError(domain: errorDomain, code: code.rawValue, userInfo: userInfo)
+
+ return returnError
+ }
+
+ /// Utility function for checking for errors in response
+ internal static func checkResponseForError(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) -> Error? {
+ if let error = error {
+ return error
+ }
+ guard let _ = data else {
+ let failureReason = "Data could not be serialized. Input data was nil."
+ let error = newError(.noData, failureReason: failureReason)
+ return error
+ }
+ return nil
+ }
+
+ /// Utility function for extracting JSON from response
+ internal static func processResponse(request: URLRequest?, response: HTTPURLResponse?, data: Data?, keyPath: String?) -> Any? {
+ let jsonResponseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments)
+ let result = jsonResponseSerializer.serializeResponse(request, response, data, nil)
+
+ let JSON: Any?
+ if let keyPath = keyPath , keyPath.isEmpty == false {
+ JSON = (result.value as AnyObject?)?.value(forKeyPath: keyPath)
+ } else {
+ JSON = result.value
+ }
+
+ return JSON
+ }
+
+ /// BaseMappable Object Serializer
+ public static func ObjectMapperSerializer(_ keyPath: String?, mapToObject object: T? = nil, context: MapContext? = nil) -> DataResponseSerializer {
+ return DataResponseSerializer { request, response, data, error in
+ if let error = checkResponseForError(request: request, response: response, data: data, error: error){
+ return .failure(error)
+ }
+
+ let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath)
+
+ if let object = object {
+ _ = Mapper(context: context, shouldIncludeNilValues: false).map(JSONObject: JSONObject, toObject: object)
+ return .success(object)
+ } else if let parsedObject = Mapper(context: context, shouldIncludeNilValues: false).map(JSONObject: JSONObject){
+ return .success(parsedObject)
+ }
+
+ let failureReason = "ObjectMapper failed to serialize response."
+ let error = newError(.dataSerializationFailed, failureReason: failureReason)
+ return .failure(error)
+ }
+ }
+
+ /// ImmutableMappable Array Serializer
+ public static func ObjectMapperImmutableSerializer(_ keyPath: String?, context: MapContext? = nil) -> DataResponseSerializer {
+ return DataResponseSerializer { request, response, data, error in
+ if let error = checkResponseForError(request: request, response: response, data: data, error: error){
+ return .failure(error)
+ }
+
+ let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath)
+
+ if let JSONObject = JSONObject,
+ let parsedObject = (try? Mapper(context: context, shouldIncludeNilValues: false).map(JSONObject: JSONObject)){
+ return .success(parsedObject)
+ }
+
+ let failureReason = "ObjectMapper failed to serialize response."
+ let error = newError(.dataSerializationFailed, failureReason: failureReason)
+ return .failure(error)
+ }
+ }
+
+ /**
+ Adds a handler to be called once the request has finished.
+
+ - parameter queue: The queue on which the completion handler is dispatched.
+ - parameter keyPath: The key path where object mapping should be performed
+ - parameter object: An object to perform the mapping on to
+ - parameter completionHandler: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper.
+
+ - returns: The request.
+ */
+ @discardableResult
+ public func responseObject(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse) -> Void) -> Self {
+ return response(queue: queue, responseSerializer: DataRequest.ObjectMapperSerializer(keyPath, mapToObject: object, context: context), completionHandler: completionHandler)
+ }
+
+ @discardableResult
+ public func responseObject(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse) -> Void) -> Self {
+ return response(queue: queue, responseSerializer: DataRequest.ObjectMapperImmutableSerializer(keyPath, context: context), completionHandler: completionHandler)
+ }
+
+ /// BaseMappable Array Serializer
+ public static func ObjectMapperArraySerializer(_ keyPath: String?, context: MapContext? = nil) -> DataResponseSerializer<[T]> {
+ return DataResponseSerializer { request, response, data, error in
+ if let error = checkResponseForError(request: request, response: response, data: data, error: error){
+ return .failure(error)
+ }
+
+ let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath)
+
+ if let parsedObject = Mapper(context: context, shouldIncludeNilValues: false).mapArray(JSONObject: JSONObject){
+ return .success(parsedObject)
+ }
+
+ let failureReason = "ObjectMapper failed to serialize response."
+ let error = newError(.dataSerializationFailed, failureReason: failureReason)
+ return .failure(error)
+ }
+ }
+
+ /// ImmutableMappable Array Serializer
+ public static func ObjectMapperImmutableArraySerializer(_ keyPath: String?, context: MapContext? = nil) -> DataResponseSerializer<[T]> {
+ return DataResponseSerializer { request, response, data, error in
+ if let error = checkResponseForError(request: request, response: response, data: data, error: error){
+ return .failure(error)
+ }
+
+ if let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath){
+
+ if let parsedObject = try? Mapper(context: context, shouldIncludeNilValues: false).mapArray(JSONObject: JSONObject){
+ return .success(parsedObject)
+ }
+ }
+
+ let failureReason = "ObjectMapper failed to serialize response."
+ let error = newError(.dataSerializationFailed, failureReason: failureReason)
+ return .failure(error)
+ }
+ }
+
+ /**
+ Adds a handler to be called once the request has finished. T: BaseMappable
+
+ - parameter queue: The queue on which the completion handler is dispatched.
+ - parameter keyPath: The key path where object mapping should be performed
+ - parameter completionHandler: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper.
+
+ - returns: The request.
+ */
+ @discardableResult
+ public func responseArray(queue: DispatchQueue? = nil, keyPath: String? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<[T]>) -> Void) -> Self {
+ return response(queue: queue, responseSerializer: DataRequest.ObjectMapperArraySerializer(keyPath, context: context), completionHandler: completionHandler)
+ }
+
+ /**
+ Adds a handler to be called once the request has finished. T: ImmutableMappable
+
+ - parameter queue: The queue on which the completion handler is dispatched.
+ - parameter keyPath: The key path where object mapping should be performed
+ - parameter completionHandler: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper.
+
+ - returns: The request.
+ */
+ @discardableResult
+ public func responseArray(queue: DispatchQueue? = nil, keyPath: String? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<[T]>) -> Void) -> Self {
+ return response(queue: queue, responseSerializer: DataRequest.ObjectMapperImmutableArraySerializer(keyPath, context: context), completionHandler: completionHandler)
+ }
+}
diff --git a/Pods/AlamofireObjectMapper/LICENSE b/Pods/AlamofireObjectMapper/LICENSE
new file mode 100644
index 0000000..cee2d0c
--- /dev/null
+++ b/Pods/AlamofireObjectMapper/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Tristan Himmelman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/Pods/AlamofireObjectMapper/README.md b/Pods/AlamofireObjectMapper/README.md
new file mode 100644
index 0000000..55c3ff9
--- /dev/null
+++ b/Pods/AlamofireObjectMapper/README.md
@@ -0,0 +1,193 @@
+AlamofireObjectMapper
+============
+[](https://travis-ci.org/tristanhimmelman/AlamofireObjectMapper)
+[](https://github.com/tristanhimmelman/AlamofireObjectMapper)
+[](https://github.com/Carthage/Carthage)
+
+
+An extension to [Alamofire](https://github.com/Alamofire/Alamofire) which automatically converts JSON response data into swift objects using [ObjectMapper](https://github.com/Hearst-DD/ObjectMapper/).
+
+# Usage
+
+Given a URL which returns weather data in the following form:
+```
+{
+ "location": "Toronto, Canada",
+ "three_day_forecast": [
+ {
+ "conditions": "Partly cloudy",
+ "day" : "Monday",
+ "temperature": 20
+ },
+ {
+ "conditions": "Showers",
+ "day" : "Tuesday",
+ "temperature": 22
+ },
+ {
+ "conditions": "Sunny",
+ "day" : "Wednesday",
+ "temperature": 28
+ }
+ ]
+}
+```
+
+You can use the extension as the follows:
+```swift
+import AlamofireObjectMapper
+
+let URL = "https://raw.githubusercontent.com/tristanhimmelman/AlamofireObjectMapper/d8bb95982be8a11a2308e779bb9a9707ebe42ede/sample_json"
+Alamofire.request(URL).responseObject { (response: DataResponse) in
+
+ let weatherResponse = response.result.value
+ print(weatherResponse?.location)
+
+ if let threeDayForecast = weatherResponse?.threeDayForecast {
+ for forecast in threeDayForecast {
+ print(forecast.day)
+ print(forecast.temperature)
+ }
+ }
+}
+```
+
+The `WeatherResponse` object in the completion handler is a custom object which you define. The only requirement is that the object must conform to [ObjectMapper's](https://github.com/Hearst-DD/ObjectMapper/) `Mappable` protocol. In the above example, the `WeatherResponse` object looks like the following:
+
+```swift
+import ObjectMapper
+
+class WeatherResponse: Mappable {
+ var location: String?
+ var threeDayForecast: [Forecast]?
+
+ required init?(map: Map){
+
+ }
+
+ func mapping(map: Map) {
+ location <- map["location"]
+ threeDayForecast <- map["three_day_forecast"]
+ }
+}
+
+class Forecast: Mappable {
+ var day: String?
+ var temperature: Int?
+ var conditions: String?
+
+ required init?(map: Map){
+
+ }
+
+ func mapping(map: Map) {
+ day <- map["day"]
+ temperature <- map["temperature"]
+ conditions <- map["conditions"]
+ }
+}
+```
+
+The extension uses Generics to allow you to create your own custom response objects. Below is the `responseObject` function definition. Just replace `T` in the completionHandler with your custom response object and the extension handles the rest:
+```swift
+public func responseObject(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse) -> Void) -> Self
+```
+The `responseObject` function has 4 optional parameters and a required completionHandler:
+- `queue`: The queue on which the completion handler is dispatched.
+- `keyPath`: The key path of the JSON where object mapping should be performed.
+- `mapToObject`: An object to perform the mapping on to.
+- `context`: A [context object](https://github.com/Hearst-DD/ObjectMapper/#mapping-context) that is passed to the mapping function.
+- `completionHandler`: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper.
+
+### Easy Mapping of Nested Objects
+
+AlamofireObjectMapper supports dot notation within keys for easy mapping of nested objects. Given the following JSON String:
+```json
+"distance" : {
+ "text" : "102 ft",
+ "value" : 31
+}
+```
+You can access the nested objects as follows:
+```swift
+func mapping(map: Map) {
+ distance <- map["distance.value"]
+}
+```
+[See complete documentation](https://github.com/Hearst-DD/ObjectMapper#easy-mapping-of-nested-objects)
+
+### KeyPath
+
+The `keyPath` variable is used to drill down into a JSON response and only map the data found at that `keyPath`. It supports nested values such as `data.weather` to drill down several levels in a JSON response.
+```swift
+let URL = "https://raw.githubusercontent.com/tristanhimmelman/AlamofireObjectMapper/2ee8f34d21e8febfdefb2b3a403f18a43818d70a/sample_keypath_json"
+let expectation = expectationWithDescription("\(URL)")
+
+Alamofire.request(URL).responseObject(keyPath: "data") { (response: DataResponse) in
+ expectation.fulfill()
+
+ let weatherResponse = response.result.value
+ print(weatherResponse?.location)
+
+ if let threeDayForecast = weatherResponse?.threeDayForecast {
+ for forecast in threeDayForecast {
+ print(forecast.day)
+ print(forecast.temperature)
+ }
+ }
+}
+```
+
+# Array Responses
+If you have an endpoint that returns data in `Array` form you can map it with the following function:
+```swift
+public func responseArray(queue queue: dispatch_queue_t? = nil, keyPath: String? = nil, completionHandler: DataResponse<[T]> -> Void) -> Self
+```
+
+For example, if your endpoint returns the following:
+```
+[
+ {
+ "conditions": "Partly cloudy",
+ "day" : "Monday",
+ "temperature": 20
+ },
+ {
+ "conditions": "Showers",
+ "day" : "Tuesday",
+ "temperature": 22
+ },
+ {
+ "conditions": "Sunny",
+ "day" : "Wednesday",
+ "temperature": 28
+ }
+]
+```
+You can request and map it as follows:
+```swift
+let URL = "https://raw.githubusercontent.com/tristanhimmelman/AlamofireObjectMapper/f583be1121dbc5e9b0381b3017718a70c31054f7/sample_array_json"
+Alamofire.request(URL).responseArray { (response: DataResponse<[Forecast]>) in
+
+ let forecastArray = response.result.value
+
+ if let forecastArray = forecastArray {
+ for forecast in forecastArray {
+ print(forecast.day)
+ print(forecast.temperature)
+ }
+ }
+}
+
+```
+
+# Installation
+AlamofireObjectMapper can be added to your project using [CocoaPods](https://cocoapods.org/) by adding the following line to your Podfile:
+```
+pod 'AlamofireObjectMapper', '~> 5.0'
+```
+
+If you're using [Carthage](https://github.com/Carthage/Carthage) you can add a dependency on AlamofireObjectMapper by adding it to your Cartfile:
+```
+github "tristanhimmelman/AlamofireObjectMapper" ~> 5.0
+```
diff --git a/Pods/CryptoSwift/LICENSE b/Pods/CryptoSwift/LICENSE
new file mode 100644
index 0000000..e52af7d
--- /dev/null
+++ b/Pods/CryptoSwift/LICENSE
@@ -0,0 +1,11 @@
+Copyright (C) 2014-2017 Marcin Krzyżanowski
+This software is provided 'as-is', without any express or implied warranty.
+
+In no event will the authors be held liable for any damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+
+- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+- This notice may not be removed or altered from any source or binary distribution.
+- Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).'
diff --git a/Pods/CryptoSwift/README.md b/Pods/CryptoSwift/README.md
new file mode 100644
index 0000000..a733f2d
--- /dev/null
+++ b/Pods/CryptoSwift/README.md
@@ -0,0 +1,510 @@
+[](#installation)
+
+[](#swift-versions-support)
+[](https://cocoapods.org/pods/CryptoSwift)
+[](https://github.com/Carthage/Carthage)
+[](https://github.com/JamitLabs/Accio)
+[](https://github.com/apple/swift-package-manager)
+
+[](http://twitter.com/krzyzanowskim)
+
+# CryptoSwift
+
+Crypto related functions and helpers for [Swift](https://swift.org) implemented in Swift. ([#PureSwift](https://twitter.com/hashtag/pureswift))
+
+**Note**: The `master` branch follows the latest currently released **version of Swift**. If you need an earlier version for an older version of Swift, you can specify its version in your `Podfile` or use the code on the branch for that version. Older branches are unsupported. Check [versions](#swift-versions-support) for details.
+
+---
+
+[Requirements](#requirements) | [Features](#features) | [Contribution](#contribution) | [Installation](#installation) | [Swift versions](#swift-versions-support) | [How-to](#how-to) | [Author](#author) | [License](#license) | [Changelog](#changelog)
+
+## Sponsorship
+
+If you (or your Company) use this work, please consider [Sponsorship](https://github.com/users/krzyzanowskim/sponsorship). This is the only option to keep the project alive, that is in your own best interrest.
+
+CryptoSwift isn't backed by a big company and is developer in my spare time that I also use to as a freelancer.
+
+## Requirements
+Good mood
+
+## Features
+
+- Easy to use
+- Convenient extensions for String and Data
+- Support for incremental updates (stream, ...)
+- iOS, Android, macOS, AppleTV, watchOS, Linux support
+
+#### Hash (Digest)
+ [MD5](http://tools.ietf.org/html/rfc1321)
+| [SHA1](http://tools.ietf.org/html/rfc3174)
+| [SHA224](http://tools.ietf.org/html/rfc6234)
+| [SHA256](http://tools.ietf.org/html/rfc6234)
+| [SHA384](http://tools.ietf.org/html/rfc6234)
+| [SHA512](http://tools.ietf.org/html/rfc6234)
+| [SHA3](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf)
+
+#### Cyclic Redundancy Check (CRC)
+ [CRC32](http://en.wikipedia.org/wiki/Cyclic_redundancy_check)
+| [CRC32C](http://en.wikipedia.org/wiki/Cyclic_redundancy_check)
+| [CRC16](http://en.wikipedia.org/wiki/Cyclic_redundancy_check)
+
+#### Cipher
+ [AES-128, AES-192, AES-256](http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf)
+| [ChaCha20](http://cr.yp.to/chacha/chacha-20080128.pdf)
+| [Rabbit](https://tools.ietf.org/html/rfc4503)
+| [Blowfish](https://www.schneier.com/academic/blowfish/)
+
+#### Message authenticators
+ [Poly1305](http://cr.yp.to/mac/poly1305-20050329.pdf)
+| [HMAC (MD5, SHA1, SHA256)](https://www.ietf.org/rfc/rfc2104.txt)
+| [CMAC](https://tools.ietf.org/html/rfc4493)
+| [CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC)
+
+#### Cipher mode of operation
+- Electronic codebook ([ECB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29))
+- Cipher-block chaining ([CBC](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29))
+- Propagating Cipher Block Chaining ([PCBC](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_Cipher_Block_Chaining_.28PCBC.29))
+- Cipher feedback ([CFB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29))
+- Output Feedback ([OFB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_Feedback_.28OFB.29))
+- Counter Mode ([CTR](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29))
+- Galois/Counter Mode ([GCM](https://csrc.nist.gov/publications/detail/sp/800-38d/final))
+- Counter with Cipher Block Chaining-Message Authentication Code ([CCM](https://csrc.nist.gov/publications/detail/sp/800-38c/final))
+
+#### Password-Based Key Derivation Function
+- [PBKDF1](http://tools.ietf.org/html/rfc2898#section-5.1) (Password-Based Key Derivation Function 1)
+- [PBKDF2](http://tools.ietf.org/html/rfc2898#section-5.2) (Password-Based Key Derivation Function 2)
+- [HKDF](https://tools.ietf.org/html/rfc5869) (HMAC-based Extract-and-Expand Key Derivation Function)
+- [Scrypt](https://tools.ietf.org/html/rfc7914) (The scrypt Password-Based Key Derivation Function)
+
+#### Data padding
+ PKCS#5
+| [PKCS#7](http://tools.ietf.org/html/rfc5652#section-6.3)
+| [Zero padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#Zero_padding)
+| No padding
+
+#### Authenticated Encryption with Associated Data (AEAD)
+- [AEAD\_CHACHA20\_POLY1305](https://tools.ietf.org/html/rfc7539#section-2.8)
+
+## Why
+[Why?](https://github.com/krzyzanowskim/CryptoSwift/issues/5) [Because I can](https://github.com/krzyzanowskim/CryptoSwift/issues/5#issuecomment-53379391).
+
+## How do I get involved?
+
+You want to help, great! Go ahead and fork our repo, make your changes and send us a pull request.
+
+## Contribution
+
+Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more information on how to help with CryptoSwift.
+
+- If you found a bug, [open an issue](https://github.com/krzyzanowskim/CryptoSwift/issues).
+- If you have a feature request, [open an issue](https://github.com/krzyzanowskim/CryptoSwift/issues).
+
+## Installation
+
+To install CryptoSwift, add it as a submodule to your project (on the top level project directory):
+
+ git submodule add https://github.com/krzyzanowskim/CryptoSwift.git
+
+It is recommended to enable [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) to gain better performance. Non-optimized build results in significantly worse performance.
+
+#### Embedded Framework
+
+Embedded frameworks require a minimum deployment target of iOS 8 or OS X Mavericks (10.9). Drag the `CryptoSwift.xcodeproj` file into your Xcode project, and add appropriate framework as a dependency to your target. Now select your App and choose the General tab for the app target. Find *Embedded Binaries* and press "+", then select `CryptoSwift.framework` (iOS, OS X, watchOS or tvOS)
+
+
+
+Sometimes "embedded framework" option is not available. In that case, you have to add new build phase for the target
+
+
+
+##### iOS, macOS, watchOS, tvOS
+
+In the project, you'll find [single scheme](https://mxcl.dev/PromiseKit/news/2016/08/Multiplatform-Single-Scheme-Xcode-Projects/) for all platforms:
+- CryptoSwift
+
+#### Swift versions support
+
+- Swift 1.2: branch [swift12](https://github.com/krzyzanowskim/CryptoSwift/tree/swift12) version <= 0.0.13
+- Swift 2.1: branch [swift21](https://github.com/krzyzanowskim/CryptoSwift/tree/swift21) version <= 0.2.3
+- Swift 2.2, 2.3: branch [swift2](https://github.com/krzyzanowskim/CryptoSwift/tree/swift2) version <= 0.5.2
+- Swift 3.1, branch [swift3](https://github.com/krzyzanowskim/CryptoSwift/tree/swift3) version <= 0.6.9
+- Swift 3.2, branch [swift32](https://github.com/krzyzanowskim/CryptoSwift/tree/swift32) version = 0.7.0
+- Swift 4.0, branch [swift4](https://github.com/krzyzanowskim/CryptoSwift/tree/swift4) version <= 0.12.0
+- Swift 4.2, branch [swift42](https://github.com/krzyzanowskim/CryptoSwift/tree/swift42) version <= 0.15.0
+- Swift 5.0, 5.1, branch [master](https://github.com/krzyzanowskim/CryptoSwift/tree/master)
+
+#### CocoaPods
+
+You can use [CocoaPods](https://cocoapods.org/pods/CryptoSwift).
+
+```ruby
+pod 'CryptoSwift', '~> 1.0'
+```
+
+Bear in mind that CocoaPods will build CryptoSwift without [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) that may impact performance. You can change it manually after installation, or use [cocoapods-wholemodule](https://github.com/jedlewison/cocoapods-wholemodule) plugin.
+
+#### Carthage
+You can use [Carthage](https://github.com/Carthage/Carthage).
+Specify in Cartfile:
+
+```ruby
+github "krzyzanowskim/CryptoSwift"
+```
+
+Run `carthage` to build the framework and drag the built CryptoSwift.framework into your Xcode project. Follow [build instructions](https://github.com/Carthage/Carthage#getting-started). [Common issues](https://github.com/krzyzanowskim/CryptoSwift/issues/492#issuecomment-330822874).
+
+#### Swift Package Manager
+
+You can use [Swift Package Manager](https://swift.org/package-manager/) and specify dependency in `Package.swift` by adding this:
+
+```swift
+.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0"))
+```
+
+See: [Package.swift - manual](http://blog.krzyzanowskim.com/2016/08/09/package-swift-manual/)
+
+#### Accio
+You can use [Accio](https://github.com/JamitLabs/Accio). Specify in `Package.swift`:
+
+```swift
+.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMajor(from: "1.0.0")),
+```
+
+Then run `accio update`.
+
+---
+
+## How-to
+
+* [Basics (data types, conversion, ...)](#basics)
+* [Digest (MD5, SHA...)](#calculate-digest)
+* [Message authenticators (HMAC, CMAC...)](#message-authenticators-1)
+* [Password-Based Key Derivation Function (PBKDF2, ...)](#password-based-key-derivation-functions)
+* [HMAC-based Key Derivation Function (HKDF)](#hmac-based-key-derivation-function)
+* [Data Padding](#data-padding)
+* [ChaCha20](#chacha20)
+* [Rabbit](#rabbit)
+* [Blowfish](#blowfish)
+* [AES - Advanced Encryption Standard](#aes)
+* [AES-GCM](#aes-gcm)
+* [Authenticated Encryption with Associated Data (AEAD)](#aead)
+
+also check [Playground](/CryptoSwift.playground/Contents.swift)
+
+##### Basics
+
+```swift
+import CryptoSwift
+```
+
+CryptoSwift uses array of bytes aka `Array` as a base type for all operations. Every data may be converted to a stream of bytes. You will find convenience functions that accept `String` or `Data`, and it will be internally converted to the array of bytes.
+
+##### Data types conversion
+
+For your convenience, **CryptoSwift** provides two functions to easily convert an array of bytes to `Data` or `Data` to an array of bytes:
+
+Data from bytes:
+
+```swift
+let data = Data( [0x01, 0x02, 0x03])
+```
+
+`Data` to `Array`
+
+```swift
+let bytes = data.bytes // [1,2,3]
+```
+
+[Hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) encoding:
+
+```swift
+let bytes = Array(hex: "0x010203") // [1,2,3]
+let hex = bytes.toHexString() // "010203"
+```
+
+Build bytes out of `String`
+```swift
+let bytes: Array = "cipherkey".bytes // Array("cipherkey".utf8)
+```
+
+Also... check out helpers that work with **Base64** encoded data:
+```swift
+"aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64ToString(cipher)
+"aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64(cipher)
+bytes.toBase64()
+```
+
+##### Calculate Digest
+
+Hashing a data or array of bytes (aka `Array`)
+```swift
+/* Hash struct usage */
+let bytes:Array = [0x01, 0x02, 0x03]
+let digest = input.md5()
+let digest = Digest.md5(bytes)
+```
+
+```swift
+let data = Data( [0x01, 0x02, 0x03])
+
+let hash = data.md5()
+let hash = data.sha1()
+let hash = data.sha224()
+let hash = data.sha256()
+let hash = data.sha384()
+let hash = data.sha512()
+```
+```swift
+do {
+ var digest = MD5()
+ let partial1 = try digest.update(withBytes: [0x31, 0x32])
+ let partial2 = try digest.update(withBytes: [0x33])
+ let result = try digest.finish()
+} catch { }
+```
+
+Hashing a String and printing result
+
+```swift
+let hash = "123".md5() // "123".bytes.md5()
+```
+
+##### Calculate CRC
+
+```swift
+bytes.crc16()
+data.crc16()
+
+bytes.crc32()
+data.crc32()
+```
+
+##### Message authenticators
+
+```swift
+// Calculate Message Authentication Code (MAC) for message
+let key:Array = [1,2,3,4,5,6,7,8,9,10,...]
+
+try Poly1305(key: key).authenticate(bytes)
+try HMAC(key: key, variant: .sha256).authenticate(bytes)
+try CMAC(key: key).authenticate(bytes)
+```
+
+##### Password-Based Key Derivation Functions
+
+```swift
+let password: Array = Array("s33krit".utf8)
+let salt: Array = Array("nacllcan".utf8)
+
+let key = try PKCS5.PBKDF2(password: password, salt: salt, iterations: 4096, keyLength: 32, variant: .sha256).calculate()
+```
+
+```swift
+let password: Array = Array("s33krit".utf8)
+let salt: Array = Array("nacllcan".utf8)
+// Scrypt implementation does not implement work parallelization, so `p` parameter will
+// increase the work time even in multicore systems
+let key = try Scrypt(password: password, salt: salt, dkLen: 64, N: 16384, r: 8, p: 1).calculate()
+```
+
+##### HMAC-based Key Derivation Function
+
+```swift
+let password: Array = Array("s33krit".utf8)
+let salt: Array = Array("nacllcan".utf8)
+
+let key = try HKDF(password: password, salt: salt, variant: .sha256).calculate()
+```
+
+
+##### Data Padding
+
+Some content-encryption algorithms assume the input length is a multiple of `k` octets, where `k` is greater than one. For such algorithms, the input shall be padded.
+
+```swift
+Padding.pkcs7.add(to: bytes, blockSize: AES.blockSize)
+```
+
+#### Working with Ciphers
+##### ChaCha20
+
+```swift
+let encrypted = try ChaCha20(key: key, iv: iv).encrypt(message)
+let decrypted = try ChaCha20(key: key, iv: iv).decrypt(encrypted)
+```
+
+##### Rabbit
+
+```swift
+let encrypted = try Rabbit(key: key, iv: iv).encrypt(message)
+let decrypted = try Rabbit(key: key, iv: iv).decrypt(encrypted)
+```
+##### Blowfish
+
+```swift
+let encrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(message)
+let decrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
+```
+
+##### AES
+
+Notice regarding padding: *Manual padding of data is optional, and CryptoSwift is using PKCS7 padding by default. If you need to manually disable/enable padding, you can do this by setting parameter for __AES__ class*
+
+Variant of AES encryption (AES-128, AES-192, AES-256) depends on given key length:
+
+- AES-128 = 16 bytes
+- AES-192 = 24 bytes
+- AES-256 = 32 bytes
+
+AES-256 example
+```swift
+try AES(key: [1,2,3,...,32], blockMode: CBC(iv: [1,2,3,...,16]), padding: .pkcs7)
+```
+
+###### All at once
+```swift
+do {
+ let aes = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap") // aes128
+ let ciphertext = try aes.encrypt(Array("Nullam quis risus eget urna mollis ornare vel eu leo.".utf8))
+} catch { }
+```
+
+###### Incremental updates
+
+Incremental operations use instance of Cryptor and encrypt/decrypt one part at a time, this way you can save on memory for large files.
+
+```swift
+do {
+ var encryptor = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap").makeEncryptor()
+
+ var ciphertext = Array()
+ // aggregate partial results
+ ciphertext += try encryptor.update(withBytes: Array("Nullam quis risus ".utf8))
+ ciphertext += try encryptor.update(withBytes: Array("eget urna mollis ".utf8))
+ ciphertext += try encryptor.update(withBytes: Array("ornare vel eu leo.".utf8))
+ // finish at the end
+ ciphertext += try encryptor.finish()
+
+ print(ciphertext.toHexString())
+} catch {
+ print(error)
+}
+```
+
+See [Playground](/CryptoSwift.playground/Contents.swift) for sample code that work with stream.
+
+###### AES Advanced usage
+```swift
+let input: Array = [0,1,2,3,4,5,6,7,8,9]
+
+let key: Array = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+let iv: Array = // Random bytes of `AES.blockSize` length
+
+do {
+ let encrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(input)
+ let decrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted)
+} catch {
+ print(error)
+}
+```
+
+AES without data padding
+
+```swift
+let input: Array = [0,1,2,3,4,5,6,7,8,9]
+let encrypted: Array = try! AES(key: Array("secret0key000000".utf8), blockMode: CBC(iv: Array("0123456789012345".utf8)), padding: .noPadding).encrypt(input)
+```
+
+Using convenience extensions
+
+```swift
+let plain = Data( [0x01, 0x02, 0x03])
+let encrypted = try! plain.encrypt(ChaCha20(key: key, iv: iv))
+let decrypted = try! encrypted.decrypt(ChaCha20(key: key, iv: iv))
+```
+
+##### AES-GCM
+
+The result of Galois/Counter Mode (GCM) encryption is ciphertext and **authentication tag**, that is later used to decryption.
+
+encryption
+
+```swift
+do {
+ // In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want.
+ let gcm = GCM(iv: iv, mode: .combined)
+ let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
+ let encrypted = try aes.encrypt(plaintext)
+ let tag = gcm.authenticationTag
+catch {
+ // failed
+}
+```
+
+decryption
+
+```swift
+do {
+ // In combined mode, the authentication tag is appended to the encrypted message. This is usually what you want.
+ let gcm = GCM(iv: iv, mode: .combined)
+ let aes = try AES(key: key, blockMode: gcm, padding: .noPadding)
+ return try aes.decrypt(encrypted)
+} catch {
+ // failed
+}
+```
+
+**Note**: GCM instance is not intended to be reused. So you can't use the same `GCM` instance from encoding to also perform decoding.
+
+##### AES-CCM
+
+The result of Counter with Cipher Block Chaining-Message Authentication Code encryption is ciphertext and **authentication tag**, that is later used to decryption.
+
+```swift
+do {
+ // The authentication tag is appended to the encrypted message.
+ let tagLength = 8
+ let ccm = CCM(iv: iv, tagLength: tagLength, messageLength: ciphertext.count - tagLength, additionalAuthenticatedData: data)
+ let aes = try AES(key: key, blockMode: ccm, padding: .noPadding)
+ return try aes.decrypt(encrypted)
+} catch {
+ // failed
+}
+```
+
+Check documentation or CCM specification for valid parameters for CCM.
+
+##### AEAD
+
+```swift
+let encrypt = try AEADChaCha20Poly1305.encrypt(plaintext, key: key, iv: nonce, authenticationHeader: header)
+let decrypt = try AEADChaCha20Poly1305.decrypt(ciphertext, key: key, iv: nonce, authenticationHeader: header, authenticationTag: tagArr: tag)
+```
+
+## Author
+
+CryptoSwift is owned and maintained by [Marcin Krzyżanowski](http://www.krzyzanowskim.com)
+
+You can follow me on Twitter at [@krzyzanowskim](http://twitter.com/krzyzanowskim) for project updates and releases.
+
+# Cryptography Notice
+
+This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See http://www.wassenaar.org/ for more information.
+
+## License
+
+Copyright (C) 2014-2017 Marcin Krzyżanowski
+This software is provided 'as-is', without any express or implied warranty.
+
+In no event will the authors be held liable for any damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+
+- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, **an acknowledgment in the product documentation is required**.
+- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+- This notice may not be removed or altered from any source or binary distribution.
+- Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).'
+
+## Changelog
+
+See [CHANGELOG](./CHANGELOG) file.
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEAD.swift b/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEAD.swift
new file mode 100644
index 0000000..6d85c04
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEAD.swift
@@ -0,0 +1,40 @@
+//
+// AEAD.swift
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+//
+
+// https://www.iana.org/assignments/aead-parameters/aead-parameters.xhtml
+
+/// Authenticated Encryption with Associated Data (AEAD)
+public protocol AEAD {
+ static var kLen: Int { get } // key length
+ static var ivRange: Range { get } // nonce length
+}
+
+extension AEAD {
+ static func calculateAuthenticationTag(authenticator: Authenticator, cipherText: Array, authenticationHeader: Array) throws -> Array {
+ let headerPadding = ((16 - (authenticationHeader.count & 0xf)) & 0xf)
+ let cipherPadding = ((16 - (cipherText.count & 0xf)) & 0xf)
+
+ var mac = authenticationHeader
+ mac += Array(repeating: 0, count: headerPadding)
+ mac += cipherText
+ mac += Array(repeating: 0, count: cipherPadding)
+ mac += UInt64(bigEndian: UInt64(authenticationHeader.count)).bytes()
+ mac += UInt64(bigEndian: UInt64(cipherText.count)).bytes()
+
+ return try authenticator.authenticate(mac)
+ }
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEADChaCha20Poly1305.swift b/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEADChaCha20Poly1305.swift
new file mode 100644
index 0000000..085f031
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEADChaCha20Poly1305.swift
@@ -0,0 +1,59 @@
+//
+// ChaCha20Poly1305.swift
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+//
+// https://tools.ietf.org/html/rfc7539#section-2.8.1
+
+/// AEAD_CHACHA20_POLY1305
+public final class AEADChaCha20Poly1305: AEAD {
+ public static let kLen = 32 // key length
+ public static var ivRange = Range(12...12)
+
+ /// Authenticated encryption
+ public static func encrypt(_ plainText: Array, key: Array, iv: Array, authenticationHeader: Array) throws -> (cipherText: Array, authenticationTag: Array) {
+ let cipher = try ChaCha20(key: key, iv: iv)
+
+ var polykey = Array(repeating: 0, count: kLen)
+ var toEncrypt = polykey
+ polykey = try cipher.encrypt(polykey)
+ toEncrypt += polykey
+ toEncrypt += plainText
+
+ let fullCipherText = try cipher.encrypt(toEncrypt)
+ let cipherText = Array(fullCipherText.dropFirst(64))
+
+ let tag = try calculateAuthenticationTag(authenticator: Poly1305(key: polykey), cipherText: cipherText, authenticationHeader: authenticationHeader)
+ return (cipherText, tag)
+ }
+
+ /// Authenticated decryption
+ public static func decrypt(_ cipherText: Array, key: Array, iv: Array, authenticationHeader: Array, authenticationTag: Array) throws -> (plainText: Array, success: Bool) {
+ let chacha = try ChaCha20(key: key, iv: iv)
+
+ let polykey = try chacha.encrypt(Array(repeating: 0, count: self.kLen))
+ let mac = try calculateAuthenticationTag(authenticator: Poly1305(key: polykey), cipherText: cipherText, authenticationHeader: authenticationHeader)
+ guard mac == authenticationTag else {
+ return (cipherText, false)
+ }
+
+ var toDecrypt = Array(reserveCapacity: cipherText.count + 64)
+ toDecrypt += polykey
+ toDecrypt += polykey
+ toDecrypt += cipherText
+ let fullPlainText = try chacha.decrypt(toDecrypt)
+ let plainText = Array(fullPlainText.dropFirst(64))
+ return (plainText, true)
+ }
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/AES.Cryptors.swift b/Pods/CryptoSwift/Sources/CryptoSwift/AES.Cryptors.swift
new file mode 100644
index 0000000..617ff7d
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/AES.Cryptors.swift
@@ -0,0 +1,35 @@
+//
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+// MARK: Cryptors
+
+extension AES: Cryptors {
+ public func makeEncryptor() throws -> Cryptor & Updatable {
+ let worker = try blockMode.worker(blockSize: AES.blockSize, cipherOperation: encrypt)
+ if worker is StreamModeWorker {
+ return try StreamEncryptor(blockSize: AES.blockSize, padding: padding, worker)
+ }
+ return try BlockEncryptor(blockSize: AES.blockSize, padding: padding, worker)
+ }
+
+ public func makeDecryptor() throws -> Cryptor & Updatable {
+ let cipherOperation: CipherOperationOnBlock = blockMode.options.contains(.useEncryptToDecrypt) == true ? encrypt : decrypt
+ let worker = try blockMode.worker(blockSize: AES.blockSize, cipherOperation: cipherOperation)
+ if worker is StreamModeWorker {
+ return try StreamDecryptor(blockSize: AES.blockSize, padding: padding, worker)
+ }
+ return try BlockDecryptor(blockSize: AES.blockSize, padding: padding, worker)
+ }
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/AES.swift b/Pods/CryptoSwift/Sources/CryptoSwift/AES.swift
new file mode 100644
index 0000000..bd4e583
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/AES.swift
@@ -0,0 +1,539 @@
+//
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+// Implementation of Gladman algorithm http://www.gladman.me.uk/AES
+//
+
+/// The Advanced Encryption Standard (AES)
+public final class AES: BlockCipher {
+ public enum Error: Swift.Error {
+ /// Invalid key
+ case invalidKeySize
+ /// Data padding is required
+ case dataPaddingRequired
+ /// Invalid Data
+ case invalidData
+ }
+
+ public enum Variant: Int {
+ case aes128 = 1, aes192, aes256
+
+ var Nk: Int { // Nk words
+ [4, 6, 8][self.rawValue - 1]
+ }
+
+ var Nb: Int { // Nb words
+ 4
+ }
+
+ var Nr: Int { // Nr
+ self.Nk + 6
+ }
+ }
+
+ private let variantNr: Int
+ private let variantNb: Int
+ private let variantNk: Int
+
+ public static let blockSize: Int = 16 // 128 /8
+ public let keySize: Int
+
+ /// AES Variant
+ public let variant: Variant
+
+ // Parameters
+ let key: Key
+ let blockMode: BlockMode
+ let padding: Padding
+
+ //
+ private lazy var expandedKey: Array> = self.expandKey(self.key, variant: self.variant)
+ private lazy var expandedKeyInv: Array> = self.expandKeyInv(self.key, variant: self.variant)
+
+ private lazy var sBoxes: (sBox: Array, invSBox: Array) = self.calculateSBox()
+ private lazy var sBox: Array = self.sBoxes.sBox
+ private lazy var sBoxInv: Array = self.sBoxes.invSBox
+
+ // Parameters for Linear Congruence Generators
+ private static let Rcon: Array = [
+ 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+ 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
+ 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
+ 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
+ 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
+ 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
+ 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
+ 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
+ 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
+ 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
+ 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
+ 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
+ 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
+ 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
+ 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
+ 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d
+ ]
+
+ private static let T0: Array = [0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0xdf2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x3010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0xbf0f0fb, 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x2f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x8f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, 0xc040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0xf05050a, 0xb59a9a2f, 0x907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x0, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 0x10f9f9e9, 0x6020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x4f5f5f1, 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0xef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0xa06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac, 0x7f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x5030306, 0x1f6f6f7, 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c]
+ private static let T0_INV: Array = [0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 0x2752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, 0x728ebb2, 0x3c2b52f, 0x9a7bc586, 0xa50837d3, 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x69f715e, 0x51106ebd, 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 0x55dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x0, 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0xfe75793, 0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 0xaba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0xb0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0xd927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x97826cd, 0xf418596e, 0x1b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x8cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 0xf7daec41, 0xe50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, 0x4ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0xc25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0]
+ private static let T1: Array = [0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x1010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x5050a0f, 0x9a9a2fb5, 0x7070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, 0x5353a6f5, 0xd1d1b968, 0x0, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, 0xf9f9e910, 0x2020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0xc0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0xb0b161d, 0xdbdbad76, 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0xa0a141e, 0x494992db, 0x6060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x8081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x3030605, 0xf6f6f701, 0xe0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, 0x8c8c038f, 0xa1a159f8, 0x89890980, 0xd0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 0x2d2d5a77, 0xf0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a]
+ private static let T1_INV: Array = [0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x3e34b93, 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0xeea4598, 0xc0fe5de1, 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x24b72e2, 0x8f1fe357, 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x837d3a5, 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, 0x8a213ef9, 0x6dd963d, 0x53eddae, 0xbde64d46, 0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, 0xa7ca147, 0xf427ce9, 0x1e84f8c9, 0x0, 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0xd090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x775af4c, 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0xbd49836, 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x99fead4, 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c, 0xca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x1a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042]
+ private static let T2: Array = [0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x1020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x4080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x50a0f05, 0x9a2fb59a, 0x70e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x9121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, 0x53a6f553, 0xd1b968d1, 0x0, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, 0xf9e910f9, 0x2040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0xc18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0xb161d0b, 0xdbad76db, 0xe0db3be0, 0x32645632, 0x3a744e3a, 0xa141e0a, 0x4992db49, 0x60c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x8101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x3060503, 0xf6f701f6, 0xe1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, 0x8c038f8c, 0xa159f8a1, 0x89098089, 0xd1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 0x2d5a772d, 0xf1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16]
+ private static let T2_INV: Array = [0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 0xcc889176, 0x2f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x8f9942b, 0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, 0x2830f287, 0xbf23b2a5, 0x302ba6a, 0x16ed5c82, 0xcf8a2b1c, 0x79a792b4, 0x7f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x506d5be, 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 0xc471055d, 0x6046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x0, 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0xefdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739, 0xf0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, 0xa0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x90e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, 0x1f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x4f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0xbfb2e41, 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0xdff4195, 0xa8397101, 0xc08deb3, 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257]
+ private static let T3: Array = [0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x2030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x80c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0xa0f0505, 0x2fb59a9a, 0xe090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, 0xa6f55353, 0xb968d1d1, 0x0, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, 0xe910f9f9, 0x4060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x58a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0xb838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0xc0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x18c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0xd868b8b, 0xf858a8a, 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x6050303, 0xf701f6f6, 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x7898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, 0x38f8c8c, 0x59f8a1a1, 0x9808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616]
+ private static let T3_INV: Array = [0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x3e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, 0x30f28728, 0x23b2a5bf, 0x2ba6a03, 0xed5c8216, 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x6d5be05, 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x532e18a, 0xa475ebf6, 0xb39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 0x71055dc4, 0x46fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x7888b89, 0xe7385b19, 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x0, 0x9838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, 0xf563885, 0x3d1ed5ae, 0x3627392d, 0xa64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, 0xcb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0xe0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, 0xdec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165, 0x9d04ea5e, 0x15d358c, 0xfa737487, 0xfb2e410b, 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x8deb30c, 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8]
+ private static let U1: Array = [0x0, 0xb0d090e, 0x161a121c, 0x1d171b12, 0x2c342438, 0x27392d36, 0x3a2e3624, 0x31233f2a, 0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362, 0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a, 0xb0d090e0, 0xbbdd99ee, 0xa6ca82fc, 0xadc78bf2, 0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca, 0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382, 0xc48cfca8, 0xcf81f5a6, 0xd296eeb4, 0xd99be7ba, 0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9, 0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1, 0x23d373ab, 0x28de7aa5, 0x35c961b7, 0x3ec468b9, 0xfe75793, 0x4ea5e9d, 0x19fd458f, 0x12f04c81, 0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029, 0xe75f8f03, 0xec52860d, 0xf1459d1f, 0xfa489411, 0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859, 0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61, 0xf66d76ad, 0xfd607fa3, 0xe07764b1, 0xeb7a6dbf, 0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987, 0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf, 0x82311ae5, 0x893c13eb, 0x942b08f9, 0x9f2601f7, 0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f, 0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967, 0x1ed5ae3d, 0x15d8a733, 0x8cfbc21, 0x3c2b52f, 0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117, 0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664, 0xa1e2694e, 0xaaef6040, 0xb7f87b52, 0xbcf5725c, 0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14, 0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c, 0x3d06dd96, 0x360bd498, 0x2b1ccf8a, 0x2011c684, 0x1132f9ae, 0x1a3ff0a0, 0x728ebb2, 0xc25e2bc, 0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4, 0x495ab1de, 0x4257b8d0, 0x5f40a3c2, 0x544daacc, 0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753, 0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b, 0xafb2a431, 0xa4bfad3f, 0xb9a8b62d, 0xb2a5bf23, 0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b, 0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3, 0x6b3e5899, 0x60335197, 0x7d244a85, 0x7629438b, 0x1f6234d1, 0x146f3ddf, 0x97826cd, 0x2752fc3, 0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb, 0x8c61d79a, 0x876cde94, 0x9a7bc586, 0x9176cc88, 0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0, 0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8, 0xf83dbbd2, 0xf330b2dc, 0xee27a9ce, 0xe52aa0c0, 0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68, 0x10856342, 0x1b886a4c, 0x69f715e, 0xd927850, 0x64d90f0a, 0x6fd40604, 0x72c31d16, 0x79ce1418, 0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020, 0x1b79aec, 0xaba93e2, 0x17ad88f0, 0x1ca081fe, 0x2d83bed4, 0x268eb7da, 0x3b99acc8, 0x3094a5c6, 0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e, 0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6, 0xb1670a0c, 0xba6a0302, 0xa77d1810, 0xac70111e, 0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526, 0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e, 0xc53b6644, 0xce366f4a, 0xd3217458, 0xd82c7d56, 0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25, 0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d, 0x2264e947, 0x2969e049, 0x347efb5b, 0x3f73f255, 0xe50cd7f, 0x55dc471, 0x184adf63, 0x1347d66d, 0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5, 0xe6e815ef, 0xede51ce1, 0xf0f207f3, 0xfbff0efd, 0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5, 0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d]
+ private static let U2: Array = [0x0, 0xd090e0b, 0x1a121c16, 0x171b121d, 0x3424382c, 0x392d3627, 0x2e36243a, 0x233f2a31, 0x68487058, 0x65417e53, 0x725a6c4e, 0x7f536245, 0x5c6c4874, 0x5165467f, 0x467e5462, 0x4b775a69, 0xd090e0b0, 0xdd99eebb, 0xca82fca6, 0xc78bf2ad, 0xe4b4d89c, 0xe9bdd697, 0xfea6c48a, 0xf3afca81, 0xb8d890e8, 0xb5d19ee3, 0xa2ca8cfe, 0xafc382f5, 0x8cfca8c4, 0x81f5a6cf, 0x96eeb4d2, 0x9be7bad9, 0xbb3bdb7b, 0xb632d570, 0xa129c76d, 0xac20c966, 0x8f1fe357, 0x8216ed5c, 0x950dff41, 0x9804f14a, 0xd373ab23, 0xde7aa528, 0xc961b735, 0xc468b93e, 0xe757930f, 0xea5e9d04, 0xfd458f19, 0xf04c8112, 0x6bab3bcb, 0x66a235c0, 0x71b927dd, 0x7cb029d6, 0x5f8f03e7, 0x52860dec, 0x459d1ff1, 0x489411fa, 0x3e34b93, 0xeea4598, 0x19f15785, 0x14f8598e, 0x37c773bf, 0x3ace7db4, 0x2dd56fa9, 0x20dc61a2, 0x6d76adf6, 0x607fa3fd, 0x7764b1e0, 0x7a6dbfeb, 0x595295da, 0x545b9bd1, 0x434089cc, 0x4e4987c7, 0x53eddae, 0x837d3a5, 0x1f2cc1b8, 0x1225cfb3, 0x311ae582, 0x3c13eb89, 0x2b08f994, 0x2601f79f, 0xbde64d46, 0xb0ef434d, 0xa7f45150, 0xaafd5f5b, 0x89c2756a, 0x84cb7b61, 0x93d0697c, 0x9ed96777, 0xd5ae3d1e, 0xd8a73315, 0xcfbc2108, 0xc2b52f03, 0xe18a0532, 0xec830b39, 0xfb981924, 0xf691172f, 0xd64d768d, 0xdb447886, 0xcc5f6a9b, 0xc1566490, 0xe2694ea1, 0xef6040aa, 0xf87b52b7, 0xf5725cbc, 0xbe0506d5, 0xb30c08de, 0xa4171ac3, 0xa91e14c8, 0x8a213ef9, 0x872830f2, 0x903322ef, 0x9d3a2ce4, 0x6dd963d, 0xbd49836, 0x1ccf8a2b, 0x11c68420, 0x32f9ae11, 0x3ff0a01a, 0x28ebb207, 0x25e2bc0c, 0x6e95e665, 0x639ce86e, 0x7487fa73, 0x798ef478, 0x5ab1de49, 0x57b8d042, 0x40a3c25f, 0x4daacc54, 0xdaec41f7, 0xd7e54ffc, 0xc0fe5de1, 0xcdf753ea, 0xeec879db, 0xe3c177d0, 0xf4da65cd, 0xf9d36bc6, 0xb2a431af, 0xbfad3fa4, 0xa8b62db9, 0xa5bf23b2, 0x86800983, 0x8b890788, 0x9c921595, 0x919b1b9e, 0xa7ca147, 0x775af4c, 0x106ebd51, 0x1d67b35a, 0x3e58996b, 0x33519760, 0x244a857d, 0x29438b76, 0x6234d11f, 0x6f3ddf14, 0x7826cd09, 0x752fc302, 0x5610e933, 0x5b19e738, 0x4c02f525, 0x410bfb2e, 0x61d79a8c, 0x6cde9487, 0x7bc5869a, 0x76cc8891, 0x55f3a2a0, 0x58faacab, 0x4fe1beb6, 0x42e8b0bd, 0x99fead4, 0x496e4df, 0x138df6c2, 0x1e84f8c9, 0x3dbbd2f8, 0x30b2dcf3, 0x27a9ceee, 0x2aa0c0e5, 0xb1477a3c, 0xbc4e7437, 0xab55662a, 0xa65c6821, 0x85634210, 0x886a4c1b, 0x9f715e06, 0x9278500d, 0xd90f0a64, 0xd406046f, 0xc31d1672, 0xce141879, 0xed2b3248, 0xe0223c43, 0xf7392e5e, 0xfa302055, 0xb79aec01, 0xba93e20a, 0xad88f017, 0xa081fe1c, 0x83bed42d, 0x8eb7da26, 0x99acc83b, 0x94a5c630, 0xdfd29c59, 0xd2db9252, 0xc5c0804f, 0xc8c98e44, 0xebf6a475, 0xe6ffaa7e, 0xf1e4b863, 0xfcedb668, 0x670a0cb1, 0x6a0302ba, 0x7d1810a7, 0x70111eac, 0x532e349d, 0x5e273a96, 0x493c288b, 0x44352680, 0xf427ce9, 0x24b72e2, 0x155060ff, 0x18596ef4, 0x3b6644c5, 0x366f4ace, 0x217458d3, 0x2c7d56d8, 0xca1377a, 0x1a83971, 0x16b32b6c, 0x1bba2567, 0x38850f56, 0x358c015d, 0x22971340, 0x2f9e1d4b, 0x64e94722, 0x69e04929, 0x7efb5b34, 0x73f2553f, 0x50cd7f0e, 0x5dc47105, 0x4adf6318, 0x47d66d13, 0xdc31d7ca, 0xd138d9c1, 0xc623cbdc, 0xcb2ac5d7, 0xe815efe6, 0xe51ce1ed, 0xf207f3f0, 0xff0efdfb, 0xb479a792, 0xb970a999, 0xae6bbb84, 0xa362b58f, 0x805d9fbe, 0x8d5491b5, 0x9a4f83a8, 0x97468da3]
+ private static let U3: Array = [0x0, 0x90e0b0d, 0x121c161a, 0x1b121d17, 0x24382c34, 0x2d362739, 0x36243a2e, 0x3f2a3123, 0x48705868, 0x417e5365, 0x5a6c4e72, 0x5362457f, 0x6c48745c, 0x65467f51, 0x7e546246, 0x775a694b, 0x90e0b0d0, 0x99eebbdd, 0x82fca6ca, 0x8bf2adc7, 0xb4d89ce4, 0xbdd697e9, 0xa6c48afe, 0xafca81f3, 0xd890e8b8, 0xd19ee3b5, 0xca8cfea2, 0xc382f5af, 0xfca8c48c, 0xf5a6cf81, 0xeeb4d296, 0xe7bad99b, 0x3bdb7bbb, 0x32d570b6, 0x29c76da1, 0x20c966ac, 0x1fe3578f, 0x16ed5c82, 0xdff4195, 0x4f14a98, 0x73ab23d3, 0x7aa528de, 0x61b735c9, 0x68b93ec4, 0x57930fe7, 0x5e9d04ea, 0x458f19fd, 0x4c8112f0, 0xab3bcb6b, 0xa235c066, 0xb927dd71, 0xb029d67c, 0x8f03e75f, 0x860dec52, 0x9d1ff145, 0x9411fa48, 0xe34b9303, 0xea45980e, 0xf1578519, 0xf8598e14, 0xc773bf37, 0xce7db43a, 0xd56fa92d, 0xdc61a220, 0x76adf66d, 0x7fa3fd60, 0x64b1e077, 0x6dbfeb7a, 0x5295da59, 0x5b9bd154, 0x4089cc43, 0x4987c74e, 0x3eddae05, 0x37d3a508, 0x2cc1b81f, 0x25cfb312, 0x1ae58231, 0x13eb893c, 0x8f9942b, 0x1f79f26, 0xe64d46bd, 0xef434db0, 0xf45150a7, 0xfd5f5baa, 0xc2756a89, 0xcb7b6184, 0xd0697c93, 0xd967779e, 0xae3d1ed5, 0xa73315d8, 0xbc2108cf, 0xb52f03c2, 0x8a0532e1, 0x830b39ec, 0x981924fb, 0x91172ff6, 0x4d768dd6, 0x447886db, 0x5f6a9bcc, 0x566490c1, 0x694ea1e2, 0x6040aaef, 0x7b52b7f8, 0x725cbcf5, 0x506d5be, 0xc08deb3, 0x171ac3a4, 0x1e14c8a9, 0x213ef98a, 0x2830f287, 0x3322ef90, 0x3a2ce49d, 0xdd963d06, 0xd498360b, 0xcf8a2b1c, 0xc6842011, 0xf9ae1132, 0xf0a01a3f, 0xebb20728, 0xe2bc0c25, 0x95e6656e, 0x9ce86e63, 0x87fa7374, 0x8ef47879, 0xb1de495a, 0xb8d04257, 0xa3c25f40, 0xaacc544d, 0xec41f7da, 0xe54ffcd7, 0xfe5de1c0, 0xf753eacd, 0xc879dbee, 0xc177d0e3, 0xda65cdf4, 0xd36bc6f9, 0xa431afb2, 0xad3fa4bf, 0xb62db9a8, 0xbf23b2a5, 0x80098386, 0x8907888b, 0x9215959c, 0x9b1b9e91, 0x7ca1470a, 0x75af4c07, 0x6ebd5110, 0x67b35a1d, 0x58996b3e, 0x51976033, 0x4a857d24, 0x438b7629, 0x34d11f62, 0x3ddf146f, 0x26cd0978, 0x2fc30275, 0x10e93356, 0x19e7385b, 0x2f5254c, 0xbfb2e41, 0xd79a8c61, 0xde94876c, 0xc5869a7b, 0xcc889176, 0xf3a2a055, 0xfaacab58, 0xe1beb64f, 0xe8b0bd42, 0x9fead409, 0x96e4df04, 0x8df6c213, 0x84f8c91e, 0xbbd2f83d, 0xb2dcf330, 0xa9ceee27, 0xa0c0e52a, 0x477a3cb1, 0x4e7437bc, 0x55662aab, 0x5c6821a6, 0x63421085, 0x6a4c1b88, 0x715e069f, 0x78500d92, 0xf0a64d9, 0x6046fd4, 0x1d1672c3, 0x141879ce, 0x2b3248ed, 0x223c43e0, 0x392e5ef7, 0x302055fa, 0x9aec01b7, 0x93e20aba, 0x88f017ad, 0x81fe1ca0, 0xbed42d83, 0xb7da268e, 0xacc83b99, 0xa5c63094, 0xd29c59df, 0xdb9252d2, 0xc0804fc5, 0xc98e44c8, 0xf6a475eb, 0xffaa7ee6, 0xe4b863f1, 0xedb668fc, 0xa0cb167, 0x302ba6a, 0x1810a77d, 0x111eac70, 0x2e349d53, 0x273a965e, 0x3c288b49, 0x35268044, 0x427ce90f, 0x4b72e202, 0x5060ff15, 0x596ef418, 0x6644c53b, 0x6f4ace36, 0x7458d321, 0x7d56d82c, 0xa1377a0c, 0xa8397101, 0xb32b6c16, 0xba25671b, 0x850f5638, 0x8c015d35, 0x97134022, 0x9e1d4b2f, 0xe9472264, 0xe0492969, 0xfb5b347e, 0xf2553f73, 0xcd7f0e50, 0xc471055d, 0xdf63184a, 0xd66d1347, 0x31d7cadc, 0x38d9c1d1, 0x23cbdcc6, 0x2ac5d7cb, 0x15efe6e8, 0x1ce1ede5, 0x7f3f0f2, 0xefdfbff, 0x79a792b4, 0x70a999b9, 0x6bbb84ae, 0x62b58fa3, 0x5d9fbe80, 0x5491b58d, 0x4f83a89a, 0x468da397]
+ private static let U4: Array = [0x0, 0xe0b0d09, 0x1c161a12, 0x121d171b, 0x382c3424, 0x3627392d, 0x243a2e36, 0x2a31233f, 0x70586848, 0x7e536541, 0x6c4e725a, 0x62457f53, 0x48745c6c, 0x467f5165, 0x5462467e, 0x5a694b77, 0xe0b0d090, 0xeebbdd99, 0xfca6ca82, 0xf2adc78b, 0xd89ce4b4, 0xd697e9bd, 0xc48afea6, 0xca81f3af, 0x90e8b8d8, 0x9ee3b5d1, 0x8cfea2ca, 0x82f5afc3, 0xa8c48cfc, 0xa6cf81f5, 0xb4d296ee, 0xbad99be7, 0xdb7bbb3b, 0xd570b632, 0xc76da129, 0xc966ac20, 0xe3578f1f, 0xed5c8216, 0xff41950d, 0xf14a9804, 0xab23d373, 0xa528de7a, 0xb735c961, 0xb93ec468, 0x930fe757, 0x9d04ea5e, 0x8f19fd45, 0x8112f04c, 0x3bcb6bab, 0x35c066a2, 0x27dd71b9, 0x29d67cb0, 0x3e75f8f, 0xdec5286, 0x1ff1459d, 0x11fa4894, 0x4b9303e3, 0x45980eea, 0x578519f1, 0x598e14f8, 0x73bf37c7, 0x7db43ace, 0x6fa92dd5, 0x61a220dc, 0xadf66d76, 0xa3fd607f, 0xb1e07764, 0xbfeb7a6d, 0x95da5952, 0x9bd1545b, 0x89cc4340, 0x87c74e49, 0xddae053e, 0xd3a50837, 0xc1b81f2c, 0xcfb31225, 0xe582311a, 0xeb893c13, 0xf9942b08, 0xf79f2601, 0x4d46bde6, 0x434db0ef, 0x5150a7f4, 0x5f5baafd, 0x756a89c2, 0x7b6184cb, 0x697c93d0, 0x67779ed9, 0x3d1ed5ae, 0x3315d8a7, 0x2108cfbc, 0x2f03c2b5, 0x532e18a, 0xb39ec83, 0x1924fb98, 0x172ff691, 0x768dd64d, 0x7886db44, 0x6a9bcc5f, 0x6490c156, 0x4ea1e269, 0x40aaef60, 0x52b7f87b, 0x5cbcf572, 0x6d5be05, 0x8deb30c, 0x1ac3a417, 0x14c8a91e, 0x3ef98a21, 0x30f28728, 0x22ef9033, 0x2ce49d3a, 0x963d06dd, 0x98360bd4, 0x8a2b1ccf, 0x842011c6, 0xae1132f9, 0xa01a3ff0, 0xb20728eb, 0xbc0c25e2, 0xe6656e95, 0xe86e639c, 0xfa737487, 0xf478798e, 0xde495ab1, 0xd04257b8, 0xc25f40a3, 0xcc544daa, 0x41f7daec, 0x4ffcd7e5, 0x5de1c0fe, 0x53eacdf7, 0x79dbeec8, 0x77d0e3c1, 0x65cdf4da, 0x6bc6f9d3, 0x31afb2a4, 0x3fa4bfad, 0x2db9a8b6, 0x23b2a5bf, 0x9838680, 0x7888b89, 0x15959c92, 0x1b9e919b, 0xa1470a7c, 0xaf4c0775, 0xbd51106e, 0xb35a1d67, 0x996b3e58, 0x97603351, 0x857d244a, 0x8b762943, 0xd11f6234, 0xdf146f3d, 0xcd097826, 0xc302752f, 0xe9335610, 0xe7385b19, 0xf5254c02, 0xfb2e410b, 0x9a8c61d7, 0x94876cde, 0x869a7bc5, 0x889176cc, 0xa2a055f3, 0xacab58fa, 0xbeb64fe1, 0xb0bd42e8, 0xead4099f, 0xe4df0496, 0xf6c2138d, 0xf8c91e84, 0xd2f83dbb, 0xdcf330b2, 0xceee27a9, 0xc0e52aa0, 0x7a3cb147, 0x7437bc4e, 0x662aab55, 0x6821a65c, 0x42108563, 0x4c1b886a, 0x5e069f71, 0x500d9278, 0xa64d90f, 0x46fd406, 0x1672c31d, 0x1879ce14, 0x3248ed2b, 0x3c43e022, 0x2e5ef739, 0x2055fa30, 0xec01b79a, 0xe20aba93, 0xf017ad88, 0xfe1ca081, 0xd42d83be, 0xda268eb7, 0xc83b99ac, 0xc63094a5, 0x9c59dfd2, 0x9252d2db, 0x804fc5c0, 0x8e44c8c9, 0xa475ebf6, 0xaa7ee6ff, 0xb863f1e4, 0xb668fced, 0xcb1670a, 0x2ba6a03, 0x10a77d18, 0x1eac7011, 0x349d532e, 0x3a965e27, 0x288b493c, 0x26804435, 0x7ce90f42, 0x72e2024b, 0x60ff1550, 0x6ef41859, 0x44c53b66, 0x4ace366f, 0x58d32174, 0x56d82c7d, 0x377a0ca1, 0x397101a8, 0x2b6c16b3, 0x25671bba, 0xf563885, 0x15d358c, 0x13402297, 0x1d4b2f9e, 0x472264e9, 0x492969e0, 0x5b347efb, 0x553f73f2, 0x7f0e50cd, 0x71055dc4, 0x63184adf, 0x6d1347d6, 0xd7cadc31, 0xd9c1d138, 0xcbdcc623, 0xc5d7cb2a, 0xefe6e815, 0xe1ede51c, 0xf3f0f207, 0xfdfbff0e, 0xa792b479, 0xa999b970, 0xbb84ae6b, 0xb58fa362, 0x9fbe805d, 0x91b58d54, 0x83a89a4f, 0x8da39746]
+
+ /// Initialize AES with variant calculated out of key length:
+ /// - 16 bytes (AES-128)
+ /// - 24 bytes (AES-192)
+ /// - 32 bytes (AES-256)
+ ///
+ /// - parameter key: Key. Length of the key decides on AES variant.
+ /// - parameter iv: Initialization Vector (Optional for some blockMode values)
+ /// - parameter blockMode: Cipher mode of operation
+ /// - parameter padding: Padding method. .pkcs7, .noPadding, .zeroPadding, ...
+ ///
+ /// - throws: AES.Error
+ ///
+ /// - returns: Instance
+ public init(key: Array, blockMode: BlockMode, padding: Padding = .pkcs7) throws {
+ self.key = Key(bytes: key)
+ self.blockMode = blockMode
+ self.padding = padding
+ self.keySize = self.key.count
+
+ // Validate key size
+ switch self.keySize * 8 {
+ case 128:
+ self.variant = .aes128
+ case 192:
+ self.variant = .aes192
+ case 256:
+ self.variant = .aes256
+ default:
+ throw Error.invalidKeySize
+ }
+
+ self.variantNb = self.variant.Nb
+ self.variantNk = self.variant.Nk
+ self.variantNr = self.variant.Nr
+ }
+
+ internal func encrypt(block: ArraySlice) -> Array? {
+ if self.blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize {
+ return Array(block)
+ }
+
+ let rounds = self.variantNr
+ let rk = self.expandedKey
+
+ let b00 = UInt32(block[block.startIndex.advanced(by: 0)])
+ let b01 = UInt32(block[block.startIndex.advanced(by: 1)]) << 8
+ let b02 = UInt32(block[block.startIndex.advanced(by: 2)]) << 16
+ let b03 = UInt32(block[block.startIndex.advanced(by: 3)]) << 24
+ var b0 = b00 | b01 | b02 | b03
+
+ let b10 = UInt32(block[block.startIndex.advanced(by: 4)])
+ let b11 = UInt32(block[block.startIndex.advanced(by: 5)]) << 8
+ let b12 = UInt32(block[block.startIndex.advanced(by: 6)]) << 16
+ let b13 = UInt32(block[block.startIndex.advanced(by: 7)]) << 24
+ var b1 = b10 | b11 | b12 | b13
+
+ let b20 = UInt32(block[block.startIndex.advanced(by: 8)])
+ let b21 = UInt32(block[block.startIndex.advanced(by: 9)]) << 8
+ let b22 = UInt32(block[block.startIndex.advanced(by: 10)]) << 16
+ let b23 = UInt32(block[block.startIndex.advanced(by: 11)]) << 24
+ var b2 = b20 | b21 | b22 | b23
+
+ let b30 = UInt32(block[block.startIndex.advanced(by: 12)])
+ let b31 = UInt32(block[block.startIndex.advanced(by: 13)]) << 8
+ let b32 = UInt32(block[block.startIndex.advanced(by: 14)]) << 16
+ let b33 = UInt32(block[block.startIndex.advanced(by: 15)]) << 24
+ var b3 = b30 | b31 | b32 | b33
+
+ let tLength = 4
+ let t = UnsafeMutablePointer.allocate(capacity: tLength)
+ t.initialize(repeating: 0, count: tLength)
+ defer {
+ t.deinitialize(count: tLength)
+ t.deallocate()
+ }
+
+ for r in 0..> 8) & 0xff)]
+ let lb02 = AES.T2[Int((t[2] >> 16) & 0xff)]
+ let lb03 = AES.T3[Int(t[3] >> 24)]
+ b0 = lb00 ^ lb01 ^ lb02 ^ lb03
+
+ let lb10 = AES.T0[Int(t[1] & 0xff)]
+ let lb11 = AES.T1[Int((t[2] >> 8) & 0xff)]
+ let lb12 = AES.T2[Int((t[3] >> 16) & 0xff)]
+ let lb13 = AES.T3[Int(t[0] >> 24)]
+ b1 = lb10 ^ lb11 ^ lb12 ^ lb13
+
+ let lb20 = AES.T0[Int(t[2] & 0xff)]
+ let lb21 = AES.T1[Int((t[3] >> 8) & 0xff)]
+ let lb22 = AES.T2[Int((t[0] >> 16) & 0xff)]
+ let lb23 = AES.T3[Int(t[1] >> 24)]
+ b2 = lb20 ^ lb21 ^ lb22 ^ lb23
+
+ let lb30 = AES.T0[Int(t[3] & 0xff)]
+ let lb31 = AES.T1[Int((t[0] >> 8) & 0xff)]
+ let lb32 = AES.T2[Int((t[1] >> 16) & 0xff)]
+ let lb33 = AES.T3[Int(t[2] >> 24)]
+ b3 = lb30 ^ lb31 ^ lb32 ^ lb33
+ }
+
+ // last round
+ let r = rounds - 1
+
+ t[0] = b0 ^ rk[r][0]
+ t[1] = b1 ^ rk[r][1]
+ t[2] = b2 ^ rk[r][2]
+ t[3] = b3 ^ rk[r][3]
+
+ // rounds
+ b0 = F1(t[0], t[1], t[2], t[3]) ^ rk[rounds][0]
+ b1 = F1(t[1], t[2], t[3], t[0]) ^ rk[rounds][1]
+ b2 = F1(t[2], t[3], t[0], t[1]) ^ rk[rounds][2]
+ b3 = F1(t[3], t[0], t[1], t[2]) ^ rk[rounds][3]
+
+ let encrypted: Array = [
+ UInt8(b0 & 0xff), UInt8((b0 >> 8) & 0xff), UInt8((b0 >> 16) & 0xff), UInt8((b0 >> 24) & 0xff),
+ UInt8(b1 & 0xff), UInt8((b1 >> 8) & 0xff), UInt8((b1 >> 16) & 0xff), UInt8((b1 >> 24) & 0xff),
+ UInt8(b2 & 0xff), UInt8((b2 >> 8) & 0xff), UInt8((b2 >> 16) & 0xff), UInt8((b2 >> 24) & 0xff),
+ UInt8(b3 & 0xff), UInt8((b3 >> 8) & 0xff), UInt8((b3 >> 16) & 0xff), UInt8((b3 >> 24) & 0xff)
+ ]
+ return encrypted
+ }
+
+ internal func decrypt(block: ArraySlice) -> Array? {
+ if self.blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize {
+ return Array(block)
+ }
+
+ let rounds = self.variantNr
+ let rk = self.expandedKeyInv
+
+ // Save miliseconds by not using `block.toUInt32Array()`
+ let b00 = UInt32(block[block.startIndex.advanced(by: 0)])
+ let b01 = UInt32(block[block.startIndex.advanced(by: 1)]) << 8
+ let b02 = UInt32(block[block.startIndex.advanced(by: 2)]) << 16
+ let b03 = UInt32(block[block.startIndex.advanced(by: 3)]) << 24
+ var b0 = b00 | b01 | b02 | b03
+
+ let b10 = UInt32(block[block.startIndex.advanced(by: 4)])
+ let b11 = UInt32(block[block.startIndex.advanced(by: 5)]) << 8
+ let b12 = UInt32(block[block.startIndex.advanced(by: 6)]) << 16
+ let b13 = UInt32(block[block.startIndex.advanced(by: 7)]) << 24
+ var b1 = b10 | b11 | b12 | b13
+
+ let b20 = UInt32(block[block.startIndex.advanced(by: 8)])
+ let b21 = UInt32(block[block.startIndex.advanced(by: 9)]) << 8
+ let b22 = UInt32(block[block.startIndex.advanced(by: 10)]) << 16
+ let b23 = UInt32(block[block.startIndex.advanced(by: 11)]) << 24
+ var b2 = b20 | b21 | b22 | b23
+
+ let b30 = UInt32(block[block.startIndex.advanced(by: 12)])
+ let b31 = UInt32(block[block.startIndex.advanced(by: 13)]) << 8
+ let b32 = UInt32(block[block.startIndex.advanced(by: 14)]) << 16
+ let b33 = UInt32(block[block.startIndex.advanced(by: 15)]) << 24
+ var b3 = b30 | b31 | b32 | b33
+
+ let tLength = 4
+ let t = UnsafeMutablePointer.allocate(capacity: tLength)
+ t.initialize(repeating: 0, count: tLength)
+ defer {
+ t.deinitialize(count: tLength)
+ t.deallocate()
+ }
+
+ for r in (2...rounds).reversed() {
+ t[0] = b0 ^ rk[r][0]
+ t[1] = b1 ^ rk[r][1]
+ t[2] = b2 ^ rk[r][2]
+ t[3] = b3 ^ rk[r][3]
+
+ let b00 = AES.T0_INV[Int(t[0] & 0xff)]
+ let b01 = AES.T1_INV[Int((t[3] >> 8) & 0xff)]
+ let b02 = AES.T2_INV[Int((t[2] >> 16) & 0xff)]
+ let b03 = AES.T3_INV[Int(t[1] >> 24)]
+ b0 = b00 ^ b01 ^ b02 ^ b03
+
+ let b10 = AES.T0_INV[Int(t[1] & 0xff)]
+ let b11 = AES.T1_INV[Int((t[0] >> 8) & 0xff)]
+ let b12 = AES.T2_INV[Int((t[3] >> 16) & 0xff)]
+ let b13 = AES.T3_INV[Int(t[2] >> 24)]
+ b1 = b10 ^ b11 ^ b12 ^ b13
+
+ let b20 = AES.T0_INV[Int(t[2] & 0xff)]
+ let b21 = AES.T1_INV[Int((t[1] >> 8) & 0xff)]
+ let b22 = AES.T2_INV[Int((t[0] >> 16) & 0xff)]
+ let b23 = AES.T3_INV[Int(t[3] >> 24)]
+ b2 = b20 ^ b21 ^ b22 ^ b23
+
+ let b30 = AES.T0_INV[Int(t[3] & 0xff)]
+ let b31 = AES.T1_INV[Int((t[2] >> 8) & 0xff)]
+ let b32 = AES.T2_INV[Int((t[1] >> 16) & 0xff)]
+ let b33 = AES.T3_INV[Int(t[0] >> 24)]
+ b3 = b30 ^ b31 ^ b32 ^ b33
+ }
+
+ // last round
+ t[0] = b0 ^ rk[1][0]
+ t[1] = b1 ^ rk[1][1]
+ t[2] = b2 ^ rk[1][2]
+ t[3] = b3 ^ rk[1][3]
+
+ // rounds
+
+ let lb00 = self.sBoxInv[Int(B0(t[0]))]
+ let lb01 = (sBoxInv[Int(B1(t[3]))] << 8)
+ let lb02 = (sBoxInv[Int(B2(t[2]))] << 16)
+ let lb03 = (sBoxInv[Int(B3(t[1]))] << 24)
+ b0 = lb00 | lb01 | lb02 | lb03 ^ rk[0][0]
+
+ let lb10 = self.sBoxInv[Int(B0(t[1]))]
+ let lb11 = (sBoxInv[Int(B1(t[0]))] << 8)
+ let lb12 = (sBoxInv[Int(B2(t[3]))] << 16)
+ let lb13 = (sBoxInv[Int(B3(t[2]))] << 24)
+ b1 = lb10 | lb11 | lb12 | lb13 ^ rk[0][1]
+
+ let lb20 = self.sBoxInv[Int(B0(t[2]))]
+ let lb21 = (sBoxInv[Int(B1(t[1]))] << 8)
+ let lb22 = (sBoxInv[Int(B2(t[0]))] << 16)
+ let lb23 = (sBoxInv[Int(B3(t[3]))] << 24)
+ b2 = lb20 | lb21 | lb22 | lb23 ^ rk[0][2]
+
+ let lb30 = self.sBoxInv[Int(B0(t[3]))]
+ let lb31 = (sBoxInv[Int(B1(t[2]))] << 8)
+ let lb32 = (sBoxInv[Int(B2(t[1]))] << 16)
+ let lb33 = (sBoxInv[Int(B3(t[0]))] << 24)
+ b3 = lb30 | lb31 | lb32 | lb33 ^ rk[0][3]
+
+ let result: Array = [
+ UInt8(b0 & 0xff), UInt8((b0 >> 8) & 0xff), UInt8((b0 >> 16) & 0xff), UInt8((b0 >> 24) & 0xff),
+ UInt8(b1 & 0xff), UInt8((b1 >> 8) & 0xff), UInt8((b1 >> 16) & 0xff), UInt8((b1 >> 24) & 0xff),
+ UInt8(b2 & 0xff), UInt8((b2 >> 8) & 0xff), UInt8((b2 >> 16) & 0xff), UInt8((b2 >> 24) & 0xff),
+ UInt8(b3 & 0xff), UInt8((b3 >> 8) & 0xff), UInt8((b3 >> 16) & 0xff), UInt8((b3 >> 24) & 0xff)
+ ]
+ return result
+ }
+}
+
+private extension AES {
+ private func expandKeyInv(_ key: Key, variant: Variant) -> Array> {
+ let rounds = self.variantNr
+ var rk2: Array> = self.expandKey(key, variant: variant)
+
+ for r in 1.. Array> {
+ func convertExpandedKey(_ expanded: Array) -> Array> {
+ expanded.batched(by: 4).map({ UInt32(bytes: $0.reversed()) }).batched(by: 4).map { Array($0) }
+ }
+
+ /*
+ * Function used in the Key Expansion routine that takes a four-byte
+ * input word and applies an S-box to each of the four bytes to
+ * produce an output word.
+ */
+ func subWord(_ word: Array) -> Array {
+ precondition(word.count == 4)
+
+ var result = word
+ for i in 0..<4 {
+ result[i] = UInt8(self.sBox[Int(word[i])])
+ }
+ return result
+ }
+
+ @inline(__always)
+ func subWordInPlace(_ word: inout Array) {
+ precondition(word.count == 4)
+ word[0] = UInt8(self.sBox[Int(word[0])])
+ word[1] = UInt8(self.sBox[Int(word[1])])
+ word[2] = UInt8(self.sBox[Int(word[2])])
+ word[3] = UInt8(self.sBox[Int(word[3])])
+ }
+
+ let wLength = self.variantNb * (self.variantNr + 1) * 4
+ let w = UnsafeMutablePointer.allocate(capacity: wLength)
+ w.initialize(repeating: 0, count: wLength)
+ defer {
+ w.deinitialize(count: wLength)
+ w.deallocate()
+ }
+
+ for i in 0..
+
+ for i in self.variantNk..(repeating: 0, count: 4)
+
+ for wordIdx in 0..<4 {
+ tmp[wordIdx] = w[4 * (i - 1) + wordIdx]
+ }
+ if (i % self.variantNk) == 0 {
+ tmp = subWord(rotateLeft(UInt32(bytes: tmp), by: 8).bytes(totalBytes: 4))
+ tmp[0] = tmp.first! ^ AES.Rcon[i / variantNk]
+ } else if self.variantNk > 6 && (i % self.variantNk) == 4 {
+ subWordInPlace(&tmp)
+ }
+
+ // xor array of bytes
+ for wordIdx in 0..<4 {
+ w[4 * i + wordIdx] = w[4 * (i - variantNk) + wordIdx] ^ tmp[wordIdx]
+ }
+ }
+ return convertExpandedKey(Array(UnsafeBufferPointer(start: w, count: wLength)))
+ }
+
+ @inline(__always)
+ private func B0(_ x: UInt32) -> UInt32 {
+ x & 0xff
+ }
+
+ @inline(__always)
+ private func B1(_ x: UInt32) -> UInt32 {
+ (x >> 8) & 0xff
+ }
+
+ @inline(__always)
+ private func B2(_ x: UInt32) -> UInt32 {
+ (x >> 16) & 0xff
+ }
+
+ @inline(__always)
+ private func B3(_ x: UInt32) -> UInt32 {
+ (x >> 24) & 0xff
+ }
+
+ @inline(__always)
+ private func F1(_ x0: UInt32, _ x1: UInt32, _ x2: UInt32, _ x3: UInt32) -> UInt32 {
+ var result: UInt32 = 0
+ result |= UInt32(self.B1(AES.T0[Int(x0 & 255)]))
+ result |= UInt32(self.B1(AES.T0[Int((x1 >> 8) & 255)])) << 8
+ result |= UInt32(self.B1(AES.T0[Int((x2 >> 16) & 255)])) << 16
+ result |= UInt32(self.B1(AES.T0[Int(x3 >> 24)])) << 24
+ return result
+ }
+
+ private func calculateSBox() -> (sBox: Array, invSBox: Array) {
+ let sboxLength = 256
+ let sbox = UnsafeMutablePointer.allocate(capacity: sboxLength)
+ let invsbox = UnsafeMutablePointer.allocate(capacity: sboxLength)
+ sbox.initialize(repeating: 0, count: sboxLength)
+ invsbox.initialize(repeating: 0, count: sboxLength)
+ defer {
+ sbox.deinitialize(count: sboxLength)
+ sbox.deallocate()
+ invsbox.deinitialize(count: sboxLength)
+ invsbox.deallocate()
+ }
+
+ sbox[0] = 0x63
+
+ var p: UInt8 = 1, q: UInt8 = 1
+
+ repeat {
+ p = p ^ (UInt8(truncatingIfNeeded: Int(p) << 1) ^ ((p & 0x80) == 0x80 ? 0x1b : 0))
+ q ^= q << 1
+ q ^= q << 2
+ q ^= q << 4
+ q ^= (q & 0x80) == 0x80 ? 0x09 : 0
+
+ let s = 0x63 ^ q ^ rotateLeft(q, by: 1) ^ rotateLeft(q, by: 2) ^ rotateLeft(q, by: 3) ^ rotateLeft(q, by: 4)
+
+ sbox[Int(p)] = UInt32(s)
+ invsbox[Int(s)] = UInt32(p)
+ } while p != 1
+
+ return (sBox: Array(UnsafeBufferPointer(start: sbox, count: sboxLength)), invSBox: Array(UnsafeBufferPointer(start: invsbox, count: sboxLength)))
+ }
+}
+
+// MARK: Cipher
+
+extension AES: Cipher {
+ public func encrypt(_ bytes: ArraySlice) throws -> Array {
+ let chunks = bytes.batched(by: AES.blockSize)
+
+ var oneTimeCryptor = try makeEncryptor()
+ var out = Array(reserveCapacity: bytes.count)
+ for chunk in chunks {
+ out += try oneTimeCryptor.update(withBytes: chunk, isLast: false)
+ }
+ // Padding may be added at the very end
+ out += try oneTimeCryptor.finish()
+
+ if self.blockMode.options.contains(.paddingRequired) && (out.count % AES.blockSize != 0) {
+ throw Error.dataPaddingRequired
+ }
+
+ return out
+ }
+
+ public func decrypt(_ bytes: ArraySlice) throws -> Array {
+ if self.blockMode.options.contains(.paddingRequired) && (bytes.count % AES.blockSize != 0) {
+ throw Error.dataPaddingRequired
+ }
+
+ var oneTimeCryptor = try makeDecryptor()
+ let chunks = bytes.batched(by: AES.blockSize)
+ if chunks.isEmpty {
+ throw Error.invalidData
+ }
+
+ var out = Array(reserveCapacity: bytes.count)
+
+ var lastIdx = chunks.startIndex
+ chunks.indices.formIndex(&lastIdx, offsetBy: chunks.count - 1)
+
+ // To properly remove padding, `isLast` has to be known when called with the last chunk of ciphertext
+ // Last chunk of ciphertext may contains padded data so next call to update(..) won't be able to remove it
+ for idx in chunks.indices {
+ out += try oneTimeCryptor.update(withBytes: chunks[idx], isLast: idx == lastIdx)
+ }
+ return out
+ }
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Array+Extension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Array+Extension.swift
new file mode 100644
index 0000000..a9c41d4
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/Array+Extension.swift
@@ -0,0 +1,148 @@
+//
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+extension Array {
+ init(reserveCapacity: Int) {
+ self = Array()
+ self.reserveCapacity(reserveCapacity)
+ }
+
+ var slice: ArraySlice {
+ self[self.startIndex ..< self.endIndex]
+ }
+}
+
+extension Array where Element == UInt8 {
+ public init(hex: String) {
+ self.init(reserveCapacity: hex.unicodeScalars.lazy.underestimatedCount)
+ var buffer: UInt8?
+ var skip = hex.hasPrefix("0x") ? 2 : 0
+ for char in hex.unicodeScalars.lazy {
+ guard skip == 0 else {
+ skip -= 1
+ continue
+ }
+ guard char.value >= 48 && char.value <= 102 else {
+ removeAll()
+ return
+ }
+ let v: UInt8
+ let c: UInt8 = UInt8(char.value)
+ switch c {
+ case let c where c <= 57:
+ v = c - 48
+ case let c where c >= 65 && c <= 70:
+ v = c - 55
+ case let c where c >= 97:
+ v = c - 87
+ default:
+ removeAll()
+ return
+ }
+ if let b = buffer {
+ append(b << 4 | v)
+ buffer = nil
+ } else {
+ buffer = v
+ }
+ }
+ if let b = buffer {
+ append(b)
+ }
+ }
+
+ public func toHexString() -> String {
+ `lazy`.reduce("") {
+ var s = String($1, radix: 16)
+ if s.count == 1 {
+ s = "0" + s
+ }
+ return $0 + s
+ }
+ }
+}
+
+extension Array where Element == UInt8 {
+ /// split in chunks with given chunk size
+ @available(*, deprecated)
+ public func chunks(size chunksize: Int) -> Array> {
+ var words = Array>()
+ words.reserveCapacity(count / chunksize)
+ for idx in stride(from: chunksize, through: count, by: chunksize) {
+ words.append(Array(self[idx - chunksize ..< idx])) // slow for large table
+ }
+ let remainder = suffix(count % chunksize)
+ if !remainder.isEmpty {
+ words.append(Array(remainder))
+ }
+ return words
+ }
+
+ public func md5() -> [Element] {
+ Digest.md5(self)
+ }
+
+ public func sha1() -> [Element] {
+ Digest.sha1(self)
+ }
+
+ public func sha224() -> [Element] {
+ Digest.sha224(self)
+ }
+
+ public func sha256() -> [Element] {
+ Digest.sha256(self)
+ }
+
+ public func sha384() -> [Element] {
+ Digest.sha384(self)
+ }
+
+ public func sha512() -> [Element] {
+ Digest.sha512(self)
+ }
+
+ public func sha2(_ variant: SHA2.Variant) -> [Element] {
+ Digest.sha2(self, variant: variant)
+ }
+
+ public func sha3(_ variant: SHA3.Variant) -> [Element] {
+ Digest.sha3(self, variant: variant)
+ }
+
+ public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
+ Checksum.crc32(self, seed: seed, reflect: reflect)
+ }
+
+ public func crc32c(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 {
+ Checksum.crc32c(self, seed: seed, reflect: reflect)
+ }
+
+ public func crc16(seed: UInt16? = nil) -> UInt16 {
+ Checksum.crc16(self, seed: seed)
+ }
+
+ public func encrypt(cipher: Cipher) throws -> [Element] {
+ try cipher.encrypt(self.slice)
+ }
+
+ public func decrypt(cipher: Cipher) throws -> [Element] {
+ try cipher.decrypt(self.slice)
+ }
+
+ public func authenticate(with authenticator: A) throws -> [Element] {
+ try authenticator.authenticate(self)
+ }
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Authenticator.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Authenticator.swift
new file mode 100644
index 0000000..90b534e
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/Authenticator.swift
@@ -0,0 +1,20 @@
+//
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+/// Message authentication code.
+public protocol Authenticator {
+ /// Calculate Message Authentication Code (MAC) for message.
+ func authenticate(_ bytes: Array) throws -> Array
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BatchedCollection.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BatchedCollection.swift
new file mode 100644
index 0000000..5438c10
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/BatchedCollection.swift
@@ -0,0 +1,63 @@
+//
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+struct BatchedCollectionIndex {
+ let range: Range
+}
+
+extension BatchedCollectionIndex: Comparable {
+ static func == (lhs: BatchedCollectionIndex, rhs: BatchedCollectionIndex) -> Bool {
+ lhs.range.lowerBound == rhs.range.lowerBound
+ }
+
+ static func < (lhs: BatchedCollectionIndex, rhs: BatchedCollectionIndex) -> Bool {
+ lhs.range.lowerBound < rhs.range.lowerBound
+ }
+}
+
+protocol BatchedCollectionType: Collection {
+ associatedtype Base: Collection
+}
+
+struct BatchedCollection: Collection {
+ let base: Base
+ let size: Int
+ typealias Index = BatchedCollectionIndex
+ private func nextBreak(after idx: Base.Index) -> Base.Index {
+ self.base.index(idx, offsetBy: self.size, limitedBy: self.base.endIndex) ?? self.base.endIndex
+ }
+
+ var startIndex: Index {
+ Index(range: self.base.startIndex.. Index {
+ Index(range: idx.range.upperBound.. Base.SubSequence {
+ self.base[idx.range]
+ }
+}
+
+extension Collection {
+ func batched(by size: Int) -> BatchedCollection {
+ BatchedCollection(base: self, size: size)
+ }
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Bit.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Bit.swift
new file mode 100644
index 0000000..8ad9558
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/Bit.swift
@@ -0,0 +1,25 @@
+//
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+public enum Bit: Int {
+ case zero
+ case one
+}
+
+extension Bit {
+ func inverted() -> Bit {
+ self == .zero ? .one : .zero
+ }
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockCipher.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockCipher.swift
new file mode 100644
index 0000000..b07f035
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockCipher.swift
@@ -0,0 +1,18 @@
+//
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+protocol BlockCipher: Cipher {
+ static var blockSize: Int { get }
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockDecryptor.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockDecryptor.swift
new file mode 100644
index 0000000..328169e
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockDecryptor.swift
@@ -0,0 +1,85 @@
+// CryptoSwift
+//
+// Copyright (C) 2014-2018 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+public class BlockDecryptor: Cryptor, Updatable {
+ private let blockSize: Int
+ private let padding: Padding
+ private var worker: CipherModeWorker
+ private var accumulated = Array()
+
+ init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws {
+ self.blockSize = blockSize
+ self.padding = padding
+ self.worker = worker
+ }
+
+ public func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array {
+ self.accumulated += bytes
+
+ // If a worker (eg GCM) can combine ciphertext + tag
+ // we need to remove tag from the ciphertext.
+ if !isLast && self.accumulated.count < self.blockSize + self.worker.additionalBufferSize {
+ return []
+ }
+
+ let accumulatedWithoutSuffix: Array
+ if self.worker.additionalBufferSize > 0 {
+ // FIXME: how slow is that?
+ accumulatedWithoutSuffix = Array(self.accumulated.prefix(self.accumulated.count - self.worker.additionalBufferSize))
+ } else {
+ accumulatedWithoutSuffix = self.accumulated
+ }
+
+ var processedBytesCount = 0
+ var plaintext = Array(reserveCapacity: accumulatedWithoutSuffix.count)
+ // Processing in a block-size manner. It's good for block modes, but bad for stream modes.
+ for var chunk in accumulatedWithoutSuffix.batched(by: self.blockSize) {
+ if isLast || (accumulatedWithoutSuffix.count - processedBytesCount) >= blockSize {
+ let isLastChunk = processedBytesCount + chunk.count == accumulatedWithoutSuffix.count
+
+ if isLast, isLastChunk, var finalizingWorker = worker as? FinalizingDecryptModeWorker {
+ chunk = try finalizingWorker.willDecryptLast(bytes: chunk + accumulated.suffix(worker.additionalBufferSize)) // tag size
+ }
+
+ if !chunk.isEmpty {
+ plaintext += worker.decrypt(block: chunk)
+ }
+
+ if isLast, isLastChunk, var finalizingWorker = worker as? FinalizingDecryptModeWorker {
+ plaintext = Array(try finalizingWorker.didDecryptLast(bytes: plaintext.slice))
+ }
+
+ processedBytesCount += chunk.count
+ }
+ }
+ accumulated.removeFirst(processedBytesCount) // super-slow
+
+ if isLast {
+ plaintext = self.padding.remove(from: plaintext, blockSize: self.blockSize)
+ }
+
+ return plaintext
+ }
+
+ public func seek(to position: Int) throws {
+ guard var worker = self.worker as? SeekableModeWorker else {
+ fatalError("Not supported")
+ }
+
+ try worker.seek(to: position)
+ self.worker = worker
+
+ accumulated = []
+ }
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockEncryptor.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockEncryptor.swift
new file mode 100644
index 0000000..1e24499
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockEncryptor.swift
@@ -0,0 +1,58 @@
+// CryptoSwift
+//
+// Copyright (C) 2014-2018 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+final class BlockEncryptor: Cryptor, Updatable {
+ private let blockSize: Int
+ private var worker: CipherModeWorker
+ private let padding: Padding
+ // Accumulated bytes. Not all processed bytes.
+ private var accumulated = Array(reserveCapacity: 16)
+
+ private var lastBlockRemainder = 0
+
+ init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws {
+ self.blockSize = blockSize
+ self.padding = padding
+ self.worker = worker
+ }
+
+ // MARK: Updatable
+
+ public func update(withBytes bytes: ArraySlice, isLast: Bool) throws -> Array {
+ self.accumulated += bytes
+
+ if isLast {
+ self.accumulated = self.padding.add(to: self.accumulated, blockSize: self.blockSize)
+ }
+
+ var encrypted = Array(reserveCapacity: accumulated.count)
+ for chunk in self.accumulated.batched(by: self.blockSize) {
+ if isLast || chunk.count == self.blockSize {
+ encrypted += self.worker.encrypt(block: chunk)
+ }
+ }
+
+ // Stream encrypts all, so it removes all elements
+ self.accumulated.removeFirst(encrypted.count)
+
+ if var finalizingWorker = worker as? FinalizingEncryptModeWorker, isLast == true {
+ encrypted = Array(try finalizingWorker.finalize(encrypt: encrypted.slice))
+ }
+
+ return encrypted
+ }
+
+ func seek(to: Int) throws {
+ fatalError("Not supported")
+ }
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockMode.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockMode.swift
new file mode 100644
index 0000000..de613c5
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockMode.swift
@@ -0,0 +1,24 @@
+//
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+public typealias CipherOperationOnBlock = (_ block: ArraySlice) -> Array?
+
+public protocol BlockMode {
+ var options: BlockModeOption { get }
+ //TODO: doesn't have to be public
+ func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker
+}
+
+typealias StreamMode = BlockMode
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockModeOptions.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockModeOptions.swift
new file mode 100644
index 0000000..3f2f7bb
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockModeOptions.swift
@@ -0,0 +1,27 @@
+//
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+public struct BlockModeOption: OptionSet {
+ public let rawValue: Int
+
+ public init(rawValue: Int) {
+ self.rawValue = rawValue
+ }
+
+ static let none = BlockModeOption(rawValue: 1 << 0)
+ static let initializationVectorRequired = BlockModeOption(rawValue: 1 << 1)
+ static let paddingRequired = BlockModeOption(rawValue: 1 << 2)
+ static let useEncryptToDecrypt = BlockModeOption(rawValue: 1 << 3)
+}
diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CBC.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CBC.swift
new file mode 100644
index 0000000..e9043fc
--- /dev/null
+++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CBC.swift
@@ -0,0 +1,70 @@
+//
+// CryptoSwift
+//
+// Copyright (C) 2014-2017 Marcin Krzyżanowski
+// This software is provided 'as-is', without any express or implied warranty.
+//
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+//
+// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required.
+// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+// - This notice may not be removed or altered from any source or binary distribution.
+//
+
+// Cipher-block chaining (CBC)
+//
+
+public struct CBC: BlockMode {
+ public enum Error: Swift.Error {
+ /// Invalid IV
+ case invalidInitializationVector
+ }
+
+ public let options: BlockModeOption = [.initializationVectorRequired, .paddingRequired]
+ private let iv: Array
+
+ public init(iv: Array) {
+ self.iv = iv
+ }
+
+ public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker {
+ if self.iv.count != blockSize {
+ throw Error.invalidInitializationVector
+ }
+
+ return CBCModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation)
+ }
+}
+
+struct CBCModeWorker: BlockModeWorker {
+ let cipherOperation: CipherOperationOnBlock
+ var blockSize: Int
+ let additionalBufferSize: Int = 0
+ private let iv: ArraySlice
+ private var prev: ArraySlice