From efcbbbf2e9350fbc6becda9abc9c0b69a9c26e14 Mon Sep 17 00:00:00 2001 From: hyesuuou <68391767+hyesuuou@users.noreply.github.com> Date: Sun, 15 May 2022 12:55:16 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20#8=20=EC=84=9C=EB=B2=84=ED=86=B5?= =?UTF-8?q?=EC=8B=A0=20Alamofire=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Instagram-Clone.xcodeproj/project.pbxproj | 76 + .../Network/Base/GeneralResponse.swift | 30 + .../Network/Base/GeneralService.swift | 30 + .../Network/Base/NetworkConstants.swift | 13 + .../Network/Base/NetworkResult.swift | 16 + .../Network/Base/URLConstants.swift | 16 + .../Network/NetworkModel/AuthRequest.swift | 12 + .../Network/NetworkModel/AuthResponse.swift | 16 + .../Network/Router/AuthRouter.swift | 71 + .../Network/Service/AuthService.swift | 49 + .../Auth/Signin/SigninViewController.swift | 2 + Instagram-Clone/Podfile | 1 + Instagram-Clone/Podfile.lock | 6 +- Instagram-Clone/Pods/Alamofire/LICENSE | 19 + Instagram-Clone/Pods/Alamofire/README.md | 227 ++ .../Pods/Alamofire/Source/AFError.swift | 870 +++++ .../Pods/Alamofire/Source/Alamofire.swift | 35 + .../Alamofire/Source/AlamofireExtended.swift | 61 + .../Source/AuthenticationInterceptor.swift | 403 +++ .../Source/CachedResponseHandler.swift | 109 + .../Pods/Alamofire/Source/Combine.swift | 655 ++++ .../Pods/Alamofire/Source/Concurrency.swift | 698 ++++ .../Source/DispatchQueue+Alamofire.swift | 37 + .../Pods/Alamofire/Source/EventMonitor.swift | 892 +++++ .../Pods/Alamofire/Source/HTTPHeaders.swift | 447 +++ .../Pods/Alamofire/Source/HTTPMethod.swift | 54 + .../Alamofire/Source/MultipartFormData.swift | 557 ++++ .../Alamofire/Source/MultipartUpload.swift | 89 + .../Source/NetworkReachabilityManager.swift | 267 ++ .../Pods/Alamofire/Source/Notifications.swift | 115 + .../Source/OperationQueue+Alamofire.swift | 49 + .../Alamofire/Source/ParameterEncoder.swift | 217 ++ .../Alamofire/Source/ParameterEncoding.swift | 321 ++ .../Pods/Alamofire/Source/Protected.swift | 161 + .../Alamofire/Source/RedirectHandler.swift | 113 + .../Pods/Alamofire/Source/Request.swift | 1912 +++++++++++ .../Alamofire/Source/RequestInterceptor.swift | 357 ++ .../Alamofire/Source/RequestTaskMap.swift | 149 + .../Pods/Alamofire/Source/Response.swift | 453 +++ .../Source/ResponseSerialization.swift | 1290 ++++++++ .../Alamofire/Source/Result+Alamofire.swift | 120 + .../Pods/Alamofire/Source/RetryPolicy.swift | 434 +++ .../Source/ServerTrustEvaluation.swift | 719 +++++ .../Pods/Alamofire/Source/Session.swift | 1265 ++++++++ .../Alamofire/Source/SessionDelegate.swift | 336 ++ .../Source/StringEncoding+Alamofire.swift | 55 + ...URLConvertible+URLRequestConvertible.swift | 105 + .../Source/URLEncodedFormEncoder.swift | 982 ++++++ .../Source/URLRequest+Alamofire.swift | 39 + .../URLSessionConfiguration+Alamofire.swift | 46 + .../Pods/Alamofire/Source/Validation.swift | 302 ++ Instagram-Clone/Pods/Manifest.lock | 6 +- .../Pods/Pods.xcodeproj/project.pbxproj | 2857 +++++++++-------- .../Alamofire/Alamofire-Info.plist | 26 + .../Alamofire/Alamofire-dummy.m | 5 + .../Alamofire/Alamofire-prefix.pch | 12 + .../Alamofire/Alamofire-umbrella.h | 16 + .../Alamofire/Alamofire.debug.xcconfig | 14 + .../Alamofire/Alamofire.modulemap | 6 + .../Alamofire/Alamofire.release.xcconfig | 14 + ...-Instagram-Clone-acknowledgements.markdown | 23 + ...ods-Instagram-Clone-acknowledgements.plist | 29 + ...ne-frameworks-Debug-input-files.xcfilelist | 1 + ...e-frameworks-Debug-output-files.xcfilelist | 1 + ...-frameworks-Release-input-files.xcfilelist | 1 + ...frameworks-Release-output-files.xcfilelist | 1 + .../Pods-Instagram-Clone-frameworks.sh | 2 + .../Pods-Instagram-Clone.debug.xcconfig | 6 +- .../Pods-Instagram-Clone.release.xcconfig | 6 +- 69 files changed, 17052 insertions(+), 1272 deletions(-) create mode 100644 Instagram-Clone/Instagram-Clone/Network/Base/GeneralResponse.swift create mode 100644 Instagram-Clone/Instagram-Clone/Network/Base/GeneralService.swift create mode 100644 Instagram-Clone/Instagram-Clone/Network/Base/NetworkConstants.swift create mode 100644 Instagram-Clone/Instagram-Clone/Network/Base/NetworkResult.swift create mode 100644 Instagram-Clone/Instagram-Clone/Network/Base/URLConstants.swift create mode 100644 Instagram-Clone/Instagram-Clone/Network/NetworkModel/AuthRequest.swift create mode 100644 Instagram-Clone/Instagram-Clone/Network/NetworkModel/AuthResponse.swift create mode 100644 Instagram-Clone/Instagram-Clone/Network/Router/AuthRouter.swift create mode 100644 Instagram-Clone/Instagram-Clone/Network/Service/AuthService.swift create mode 100644 Instagram-Clone/Pods/Alamofire/LICENSE create mode 100644 Instagram-Clone/Pods/Alamofire/README.md create mode 100644 Instagram-Clone/Pods/Alamofire/Source/AFError.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/Alamofire.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/AlamofireExtended.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/AuthenticationInterceptor.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/CachedResponseHandler.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/Combine.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/Concurrency.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/EventMonitor.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/HTTPHeaders.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/HTTPMethod.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/MultipartFormData.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/MultipartUpload.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/NetworkReachabilityManager.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/Notifications.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/OperationQueue+Alamofire.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/ParameterEncoder.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/ParameterEncoding.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/Protected.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/RedirectHandler.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/Request.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/RequestInterceptor.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/RequestTaskMap.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/Response.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/ResponseSerialization.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/Result+Alamofire.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/RetryPolicy.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/ServerTrustEvaluation.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/Session.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/SessionDelegate.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/StringEncoding+Alamofire.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/URLConvertible+URLRequestConvertible.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/URLEncodedFormEncoder.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/URLRequest+Alamofire.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/URLSessionConfiguration+Alamofire.swift create mode 100644 Instagram-Clone/Pods/Alamofire/Source/Validation.swift create mode 100644 Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-Info.plist create mode 100644 Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-dummy.m create mode 100644 Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-prefix.pch create mode 100644 Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-umbrella.h create mode 100644 Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.debug.xcconfig create mode 100644 Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.modulemap create mode 100644 Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.release.xcconfig diff --git a/Instagram-Clone/Instagram-Clone.xcodeproj/project.pbxproj b/Instagram-Clone/Instagram-Clone.xcodeproj/project.pbxproj index eb67674..ce0d6d4 100644 --- a/Instagram-Clone/Instagram-Clone.xcodeproj/project.pbxproj +++ b/Instagram-Clone/Instagram-Clone.xcodeproj/project.pbxproj @@ -37,6 +37,15 @@ 15963F7D2800AFC2003C7A14 /* Storyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15963F7C2800AFC2003C7A14 /* Storyboard.swift */; }; 15963F7F2800B05A003C7A14 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15963F7E2800B05A003C7A14 /* ViewController.swift */; }; 15963F812800B0FB003C7A14 /* InstagramTitleLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15963F802800B0FB003C7A14 /* InstagramTitleLabel.swift */; }; + 15F0B9402830945C008A300E /* NetworkResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B93F2830945C008A300E /* NetworkResult.swift */; }; + 15F0B94228309474008A300E /* URLConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B94128309474008A300E /* URLConstants.swift */; }; + 15F0B944283094F2008A300E /* AuthRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B943283094F2008A300E /* AuthRouter.swift */; }; + 15F0B94A2830964E008A300E /* AuthRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B9492830964E008A300E /* AuthRequest.swift */; }; + 15F0B94C28309655008A300E /* AuthResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B94B28309655008A300E /* AuthResponse.swift */; }; + 15F0B94E2830996D008A300E /* GeneralResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B94D2830996D008A300E /* GeneralResponse.swift */; }; + 15F0B95028309BE5008A300E /* NetworkConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B94F28309BE5008A300E /* NetworkConstants.swift */; }; + 15F0B95228309C2C008A300E /* GeneralService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B95128309C2C008A300E /* GeneralService.swift */; }; + 15F0B95428309C90008A300E /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B95328309C90008A300E /* AuthService.swift */; }; 6B32C10577BFCF0CC42F4629 /* Pods_Instagram_Clone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 541B2B5ED91686F41F07A0A8 /* Pods_Instagram_Clone.framework */; }; /* End PBXBuildFile section */ @@ -73,6 +82,15 @@ 15963F7C2800AFC2003C7A14 /* Storyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storyboard.swift; sourceTree = ""; }; 15963F7E2800B05A003C7A14 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 15963F802800B0FB003C7A14 /* InstagramTitleLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstagramTitleLabel.swift; sourceTree = ""; }; + 15F0B93F2830945C008A300E /* NetworkResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkResult.swift; sourceTree = ""; }; + 15F0B94128309474008A300E /* URLConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLConstants.swift; sourceTree = ""; }; + 15F0B943283094F2008A300E /* AuthRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRouter.swift; sourceTree = ""; }; + 15F0B9492830964E008A300E /* AuthRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthRequest.swift; sourceTree = ""; }; + 15F0B94B28309655008A300E /* AuthResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthResponse.swift; sourceTree = ""; }; + 15F0B94D2830996D008A300E /* GeneralResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralResponse.swift; sourceTree = ""; }; + 15F0B94F28309BE5008A300E /* NetworkConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkConstants.swift; sourceTree = ""; }; + 15F0B95128309C2C008A300E /* GeneralService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralService.swift; sourceTree = ""; }; + 15F0B95328309C90008A300E /* AuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; 2FD571BBDA6B7266B6880E1A /* Pods-Instagram-Clone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Instagram-Clone.debug.xcconfig"; path = "Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.debug.xcconfig"; sourceTree = ""; }; 541B2B5ED91686F41F07A0A8 /* Pods_Instagram_Clone.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Instagram_Clone.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A9F2CFFA6199E7BEFAA4F976 /* Pods-Instagram-Clone.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Instagram-Clone.release.xcconfig"; path = "Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.release.xcconfig"; sourceTree = ""; }; @@ -160,6 +178,7 @@ 15963F3427FF634A003C7A14 /* Instagram-Clone */ = { isa = PBXGroup; children = ( + 15F0B93C2830943E008A300E /* Network */, 15963F692800A27B003C7A14 /* Resource */, 15963F682800A267003C7A14 /* Application */, 15963F5428009F9F003C7A14 /* Presentation */, @@ -298,6 +317,54 @@ path = Main; sourceTree = ""; }; + 15F0B93C2830943E008A300E /* Network */ = { + isa = PBXGroup; + children = ( + 15F0B94628309514008A300E /* Service */, + 15F0B9452830950D008A300E /* NetworkModel */, + 15F0B93E2830944A008A300E /* Router */, + 15F0B93D28309444008A300E /* Base */, + ); + path = Network; + sourceTree = ""; + }; + 15F0B93D28309444008A300E /* Base */ = { + isa = PBXGroup; + children = ( + 15F0B93F2830945C008A300E /* NetworkResult.swift */, + 15F0B94F28309BE5008A300E /* NetworkConstants.swift */, + 15F0B94128309474008A300E /* URLConstants.swift */, + 15F0B94D2830996D008A300E /* GeneralResponse.swift */, + 15F0B95128309C2C008A300E /* GeneralService.swift */, + ); + path = Base; + sourceTree = ""; + }; + 15F0B93E2830944A008A300E /* Router */ = { + isa = PBXGroup; + children = ( + 15F0B943283094F2008A300E /* AuthRouter.swift */, + ); + path = Router; + sourceTree = ""; + }; + 15F0B9452830950D008A300E /* NetworkModel */ = { + isa = PBXGroup; + children = ( + 15F0B9492830964E008A300E /* AuthRequest.swift */, + 15F0B94B28309655008A300E /* AuthResponse.swift */, + ); + path = NetworkModel; + sourceTree = ""; + }; + 15F0B94628309514008A300E /* Service */ = { + isa = PBXGroup; + children = ( + 15F0B95328309C90008A300E /* AuthService.swift */, + ); + path = Service; + sourceTree = ""; + }; 35A398614AFD2EECA4B32C8D /* Pods */ = { isa = PBXGroup; children = ( @@ -458,23 +525,32 @@ buildActionMask = 2147483647; files = ( 15963F632800A0C9003C7A14 /* AuthCompleteViewController.swift in Sources */, + 15F0B94228309474008A300E /* URLConstants.swift in Sources */, 15963F6E2800A65D003C7A14 /* InstagramTextField.swift in Sources */, + 15F0B94A2830964E008A300E /* AuthRequest.swift in Sources */, 1521D083281280C700A9C29B /* MainTabBarController.swift in Sources */, 15963F582800A06F003C7A14 /* SigninViewController.swift in Sources */, + 15F0B95228309C2C008A300E /* GeneralService.swift in Sources */, 15963F7F2800B05A003C7A14 /* ViewController.swift in Sources */, 15963F7D2800AFC2003C7A14 /* Storyboard.swift in Sources */, + 15F0B95028309BE5008A300E /* NetworkConstants.swift in Sources */, + 15F0B944283094F2008A300E /* AuthRouter.swift in Sources */, 15858D562800B7BD00332653 /* InstagramSubtitleLabel.swift in Sources */, 15963F3627FF634A003C7A14 /* AppDelegate.swift in Sources */, 15963F7A2800AAF9003C7A14 /* BaseViewController.swift in Sources */, 15963F3827FF634A003C7A14 /* SceneDelegate.swift in Sources */, + 15F0B94E2830996D008A300E /* GeneralResponse.swift in Sources */, 15963F652800A0D7003C7A14 /* SignupNameViewController.swift in Sources */, 15963F812800B0FB003C7A14 /* InstagramTitleLabel.swift in Sources */, 15963F6C2800A2F6003C7A14 /* InstagramBlueButton.swift in Sources */, 15963F672800A0E2003C7A14 /* SignupPasswordViewController.swift in Sources */, 15963F772800A8F4003C7A14 /* Image.swift in Sources */, + 15F0B95428309C90008A300E /* AuthService.swift in Sources */, 15858D972802B5CC00332653 /* AuthProtocol.swift in Sources */, + 15F0B94C28309655008A300E /* AuthResponse.swift in Sources */, 15963F752800A8CD003C7A14 /* Const.swift in Sources */, 15858D952802A04200332653 /* UITextField+.swift in Sources */, + 15F0B9402830945C008A300E /* NetworkResult.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Instagram-Clone/Instagram-Clone/Network/Base/GeneralResponse.swift b/Instagram-Clone/Instagram-Clone/Network/Base/GeneralResponse.swift new file mode 100644 index 0000000..84609f0 --- /dev/null +++ b/Instagram-Clone/Instagram-Clone/Network/Base/GeneralResponse.swift @@ -0,0 +1,30 @@ +// +// GeneralResponse.swift +// Instagram-Clone +// +// Created by 김혜수 on 2022/05/15. +// + +import Foundation + +struct GeneralResponse: Codable { + var status: Int + var success: Bool? + var message: String? + var data: T? + + enum CodingKeys: String, CodingKey { + case message + case success + case data + case status + } + + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + message = (try? values.decode(String.self, forKey: .message)) ?? "" + success = (try? values.decode(Bool.self, forKey: .success)) ?? nil + data = (try? values.decode(T.self, forKey: .data)) ?? nil + status = (try? values.decode(Int.self, forKey: .status)) ?? 0 + } +} diff --git a/Instagram-Clone/Instagram-Clone/Network/Base/GeneralService.swift b/Instagram-Clone/Instagram-Clone/Network/Base/GeneralService.swift new file mode 100644 index 0000000..e63c00c --- /dev/null +++ b/Instagram-Clone/Instagram-Clone/Network/Base/GeneralService.swift @@ -0,0 +1,30 @@ +// +// GeneralService.swift +// Instagram-Clone +// +// Created by 김혜수 on 2022/05/15. +// + +import Foundation + +struct GeneralService { + + static func judgeStatus(by statusCode: Int, _ data: Data, _ : T.Type) -> NetworkResult { + let decoder = JSONDecoder() + guard let decodedData = try? decoder.decode(GeneralResponse.self, from: data) + else { return .pathErr } + print(decodedData) + switch statusCode { + case 200: + return .success(decodedData.data) + case 201..<300: + return .success(decodedData.status) + case 400..<500: + return .requestErr(decodedData.status) + case 500: + return .serverErr + default: + return .networkFail + } + } +} diff --git a/Instagram-Clone/Instagram-Clone/Network/Base/NetworkConstants.swift b/Instagram-Clone/Instagram-Clone/Network/Base/NetworkConstants.swift new file mode 100644 index 0000000..5128483 --- /dev/null +++ b/Instagram-Clone/Instagram-Clone/Network/Base/NetworkConstants.swift @@ -0,0 +1,13 @@ +// +// NetworkConstant.swift +// Instagram-Clone +// +// Created by 김혜수 on 2022/05/15. +// + +import Foundation + +struct NetworkConstants { + + static let header = ["Content-Type": "application/json"] +} diff --git a/Instagram-Clone/Instagram-Clone/Network/Base/NetworkResult.swift b/Instagram-Clone/Instagram-Clone/Network/Base/NetworkResult.swift new file mode 100644 index 0000000..690e74f --- /dev/null +++ b/Instagram-Clone/Instagram-Clone/Network/Base/NetworkResult.swift @@ -0,0 +1,16 @@ +// +// NetworkResult.swift +// Instagram-Clone +// +// Created by 김혜수 on 2022/05/15. +// + +import Foundation + +enum NetworkResult { + case success(T) + case requestErr(T) + case pathErr + case serverErr + case networkFail +} diff --git a/Instagram-Clone/Instagram-Clone/Network/Base/URLConstants.swift b/Instagram-Clone/Instagram-Clone/Network/Base/URLConstants.swift new file mode 100644 index 0000000..b8d685a --- /dev/null +++ b/Instagram-Clone/Instagram-Clone/Network/Base/URLConstants.swift @@ -0,0 +1,16 @@ +// +// URLConstants.swift +// Instagram-Clone +// +// Created by 김혜수 on 2022/05/15. +// + +import Foundation + +struct URLConstants { + + static let baseURL = "http://13.124.62.236/" + + static let authSignup = "/auth/signup" + static let authSignin = "/auth/signin" +} diff --git a/Instagram-Clone/Instagram-Clone/Network/NetworkModel/AuthRequest.swift b/Instagram-Clone/Instagram-Clone/Network/NetworkModel/AuthRequest.swift new file mode 100644 index 0000000..792a0a5 --- /dev/null +++ b/Instagram-Clone/Instagram-Clone/Network/NetworkModel/AuthRequest.swift @@ -0,0 +1,12 @@ +// +// SigninRequest.swift +// Instagram-Clone +// +// Created by 김혜수 on 2022/05/15. +// + +import Foundation + +struct AuthRequest: Codable { + let name, email, password: String +} diff --git a/Instagram-Clone/Instagram-Clone/Network/NetworkModel/AuthResponse.swift b/Instagram-Clone/Instagram-Clone/Network/NetworkModel/AuthResponse.swift new file mode 100644 index 0000000..6267c77 --- /dev/null +++ b/Instagram-Clone/Instagram-Clone/Network/NetworkModel/AuthResponse.swift @@ -0,0 +1,16 @@ +// +// SigninResponse.swift +// Instagram-Clone +// +// Created by 김혜수 on 2022/05/15. +// + +import Foundation + +struct SigninResponse: Codable { + let name, email: String +} + +struct SignupResponse: Codable { + let id: Int +} diff --git a/Instagram-Clone/Instagram-Clone/Network/Router/AuthRouter.swift b/Instagram-Clone/Instagram-Clone/Network/Router/AuthRouter.swift new file mode 100644 index 0000000..f8ffe28 --- /dev/null +++ b/Instagram-Clone/Instagram-Clone/Network/Router/AuthRouter.swift @@ -0,0 +1,71 @@ +// +// AuthRouter.swift +// Instagram-Clone +// +// Created by 김혜수 on 2022/05/15. +// + +import Foundation + +import Alamofire + +enum UserRouter: URLRequestConvertible { + + case authSignin(login: AuthRequest) + case authSignup(join: AuthRequest) + + var baseURL: URL { + return URL(string: URLConstants.baseURL)! + } + + var method: HTTPMethod { + switch self { + case .authSignin, .authSignup: + return .post + } + } + + var path: String { + switch self { + case .authSignin: + return URLConstants.authSignin + case .authSignup: + return URLConstants.authSignup + } + } + + var headers: [String: String] { + switch self { + case .authSignin, .authSignup: + return NetworkConstants.header + } + } + + var parameters: [String: String] { + switch self { + case .authSignin(let signin): + return ["name": signin.name, + "email": signin.email, + "password": signin.password] + case .authSignup(let signup): + return ["email": signup.email, + "name": signup.name, + "password": signup.password] + } + } + + func asURLRequest() throws -> URLRequest { + let url = baseURL.appendingPathComponent(path) + + var request = URLRequest(url: url) + request.method = method + request.headers = HTTPHeaders(headers) + + switch self { + case .authSignin, .authSignup: + request = try JSONParameterEncoder().encode(parameters, into: request) + } + + return request + } +} diff --git a/Instagram-Clone/Instagram-Clone/Network/Service/AuthService.swift b/Instagram-Clone/Instagram-Clone/Network/Service/AuthService.swift new file mode 100644 index 0000000..d0e5b7d --- /dev/null +++ b/Instagram-Clone/Instagram-Clone/Network/Service/AuthService.swift @@ -0,0 +1,49 @@ +// +// AuthService.swift +// Instagram-Clone +// +// Created by 김혜수 on 2022/05/15. +// + +import Foundation + +import Alamofire + +struct AuthService { + + static let shared = AuthService() + + func postSignin(user: AuthRequest, + completion: @escaping (NetworkResult) -> Void) { + AF.request(UserRouter.authSignin(login: user)) + .validate(statusCode: 200...500) + .responseData { res in + switch res.result { + case.success(let data): + let statusCode = res.response?.statusCode + let data = data + let networkResult = GeneralService.judgeStatus(by: statusCode ?? 0, data, SigninResponse.self) + completion(networkResult) + case .failure(let err): + print(err) + } + } + } + + func postSignup(user: AuthRequest, + completion: @escaping (NetworkResult) -> Void) { + AF.request(UserRouter.authSignup(join: user)) + .validate(statusCode: 200...500) + .responseData { res in + switch res.result { + case.success(let data): + let statusCode = res.response?.statusCode + let data = data + let networkResult = GeneralService.judgeStatus(by: statusCode ?? 0, data, SignupResponse.self) + completion(networkResult) + case .failure(let err): + print(err) + } + } + } +} diff --git a/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signin/SigninViewController.swift b/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signin/SigninViewController.swift index ba94e1c..5195fdd 100644 --- a/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signin/SigninViewController.swift +++ b/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signin/SigninViewController.swift @@ -7,6 +7,8 @@ import UIKit +import Alamofire + final class SigninViewController: BaseViewController, AuthProtocol { // MARK: - Property diff --git a/Instagram-Clone/Podfile b/Instagram-Clone/Podfile index d367a3e..c552e9d 100644 --- a/Instagram-Clone/Podfile +++ b/Instagram-Clone/Podfile @@ -9,5 +9,6 @@ target 'Instagram-Clone' do pod 'RxSwift', '6.2.0' pod 'RxCocoa', '6.2.0' pod 'SwiftLint' +pod 'Alamofire' end diff --git a/Instagram-Clone/Podfile.lock b/Instagram-Clone/Podfile.lock index 18a8a45..06a495b 100644 --- a/Instagram-Clone/Podfile.lock +++ b/Instagram-Clone/Podfile.lock @@ -1,4 +1,5 @@ PODS: + - Alamofire (5.5.0) - RxCocoa (6.2.0): - RxRelay (= 6.2.0) - RxSwift (= 6.2.0) @@ -8,23 +9,26 @@ PODS: - SwiftLint (0.46.3) DEPENDENCIES: + - Alamofire - RxCocoa (= 6.2.0) - RxSwift (= 6.2.0) - SwiftLint SPEC REPOS: trunk: + - Alamofire - RxCocoa - RxRelay - RxSwift - SwiftLint SPEC CHECKSUMS: + Alamofire: 1c4fb5369c3fe93d2857c780d8bbe09f06f97e7c RxCocoa: 4baf94bb35f2c0ab31bc0cb9f1900155f646ba42 RxRelay: e72dbfd157807478401ef1982e1c61c945c94b2f RxSwift: d356ab7bee873611322f134c5f9ef379fa183d8f SwiftLint: ae76d82f056734f853c8cd0371503252c606c482 -PODFILE CHECKSUM: a922d42acc1b5e95ff8835ad84c846cf2ad563ec +PODFILE CHECKSUM: 55ed290f4298d5b68bfee2b32951a89f82fa6199 COCOAPODS: 1.11.2 diff --git a/Instagram-Clone/Pods/Alamofire/LICENSE b/Instagram-Clone/Pods/Alamofire/LICENSE new file mode 100644 index 0000000..6b4d719 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014-2021 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/Instagram-Clone/Pods/Alamofire/README.md b/Instagram-Clone/Pods/Alamofire/README.md new file mode 100644 index 0000000..c220900 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/README.md @@ -0,0 +1,227 @@ +![Alamofire: Elegant Networking in Swift](https://raw.githubusercontent.com/Alamofire/Alamofire/master/Resources/AlamofireLogo.png) + +[![Swift](https://img.shields.io/badge/Swift-5.3_5.4_5.5-orange?style=flat-square)](https://img.shields.io/badge/Swift-5.3_5.4_5.5-Orange?style=flat-square) +[![Platforms](https://img.shields.io/badge/Platforms-macOS_iOS_tvOS_watchOS_Linux_Windows-yellowgreen?style=flat-square)](https://img.shields.io/badge/Platforms-macOS_iOS_tvOS_watchOS_Linux_Windows-Green?style=flat-square) +[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/Alamofire.svg?style=flat-square)](https://img.shields.io/cocoapods/v/Alamofire.svg) +[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat-square)](https://github.com/Carthage/Carthage) +[![Swift Package Manager](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat-square)](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat-square) +[![Twitter](https://img.shields.io/badge/twitter-@AlamofireSF-blue.svg?style=flat-square)](https://twitter.com/AlamofireSF) +[![Swift Forums](https://img.shields.io/badge/Swift_Forums-Alamofire-orange?style=flat-square)](https://forums.swift.org/c/related-projects/alamofire/37) + +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) +- [Contributing](#contributing) +- [Usage](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#using-alamofire) + - [**Introduction -**](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#introduction) [Making Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#making-requests), [Response Handling](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-handling), [Response Validation](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-validation), [Response Caching](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-caching) + - **HTTP -** [HTTP Methods](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#http-methods), [Parameters and Parameter Encoder](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md##request-parameters-and-parameter-encoders), [HTTP Headers](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#http-headers), [Authentication](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#authentication) + - **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), [Session Delegate](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#sessiondelegate), [Request](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#request) + - **Routing -** [Routing Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#routing-requests), [Adapting and Retrying Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#adapting-and-retrying-requests-with-requestinterceptor) + - **Model Objects -** [Custom Response Handlers](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#customizing-response-handlers) + - **Advanced Concurrency -** [Swift Concurrency](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#using-alamofire-with-swift-concurrency) and [Combine](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#using-alamofire-with-combine) + - **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] Swift Concurrency Support Back to iOS 13, macOS 10.15, tvOS 13, and watchOS 6. +- [x] Combine Support +- [x] URL / JSON 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 + +| Platform | Minimum Swift Version | Installation | Status | +| --- | --- | --- | --- | +| iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ | 5.3 | [CocoaPods](#cocoapods), [Carthage](#carthage), [Swift Package Manager](#swift-package-manager), [Manual](#manually) | Fully Tested | +| Linux | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported | +| Windows | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported | + +#### Known Issues on Linux and Windows + +Alamofire builds on Linux and Windows but there are missing features and many issues in the underlying `swift-corelibs-foundation` that prevent full functionality and may cause crashes. These include: +- `ServerTrustManager` and associated certificate functionality is unavailable, so there is no certificate pinning and no client certificate support. +- Various methods of HTTP authentication may crash, including HTTP Basic and HTTP Digest. Crashes may occur if responses contain server challenges. +- Cache control through `CachedResponseHandler` and associated APIs is unavailable, as the underlying delegate methods aren't called. +- `URLSessionTaskMetrics` are never gathered. + +Due to these issues, Alamofire is unsupported on Linux and Windows. Please report any crashes to the [Swift bug reporter](https://bugs.swift.org). + +## Migration Guides + +- [Alamofire 5.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%205.0%20Migration%20Guide.md) +- [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** using Alamofire, 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 here on GitHub and follow the guide. The more detail the better! + +## Installation + +### CocoaPods + +[CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate Alamofire into your Xcode project using CocoaPods, specify it in your `Podfile`: + +```ruby +pod 'Alamofire', '~> 5.5' +``` + +### Carthage + +[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate Alamofire into your Xcode project using Carthage, specify it in your `Cartfile`: + +```ogdl +github "Alamofire/Alamofire" ~> 5.5 +``` + +### 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 +dependencies: [ + .package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.5.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 macOS. + + > You can verify which one you selected by inspecting the build log for your project. The build target for `Alamofire` will be listed as `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. + +## Contributing + +Before contributing to Alamofire, please read the instructions detailed in our [contribution guide](https://github.com/Alamofire/Alamofire/blob/master/CONTRIBUTING.md). + +## 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 the test case +- `rdar://26870455` - Background URL Session Configurations do not work in the simulator +- `rdar://26849668` - Some URLProtocol APIs do not properly handle `URLRequest` + +## 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): 9/1/17 in Xcode 9 beta 6. +- [`rdar://36082113`](http://openradar.appspot.com/radar?id=4942308441063424) - `URLSessionTaskMetrics` failing to link on watchOS 3.0+ + - (Resolved): Just add `CFNetwork` to your linked frameworks. +- `FB7624529` - `urlSession(_:task:didFinishCollecting:)` never called on watchOS + - (Resolved): Metrics now collected on watchOS 7+. + +## 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. + +## 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 Foundation 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. + +[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W34WPEE74APJQ) + +## Supporters + +[MacStadium](https://macstadium.com) provides Alamofire with a free, hosted Mac mini. + +![Powered by MacStadium](https://raw.githubusercontent.com/Alamofire/Alamofire/master/Resources/MacStadiumLogo.png) + +## License + +Alamofire is released under the MIT license. [See LICENSE](https://github.com/Alamofire/Alamofire/blob/master/LICENSE) for details. diff --git a/Instagram-Clone/Pods/Alamofire/Source/AFError.swift b/Instagram-Clone/Pods/Alamofire/Source/AFError.swift new file mode 100644 index 0000000..8cd60c7 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/AFError.swift @@ -0,0 +1,870 @@ +// +// AFError.swift +// +// Copyright (c) 2014-2018 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. +public enum AFError: Error { + /// The underlying reason the `.multipartEncodingFailed` error occurred. + public enum MultipartEncodingFailureReason { + /// The `fileURL` provided for reading an encodable body part isn't a file `URL`. + case bodyPartURLInvalid(url: URL) + /// The filename of the `fileURL` provided has either an empty `lastPathComponent` or `pathExtension. + case bodyPartFilenameInvalid(in: URL) + /// The file at the `fileURL` provided was not reachable. + case bodyPartFileNotReachable(at: URL) + /// Attempting to check the reachability of the `fileURL` provided threw an error. + case bodyPartFileNotReachableWithError(atURL: URL, error: Error) + /// The file at the `fileURL` provided is actually a directory. + case bodyPartFileIsDirectory(at: URL) + /// The size of the file at the `fileURL` provided was not returned by the system. + case bodyPartFileSizeNotAvailable(at: URL) + /// The attempt to find the size of the file at the `fileURL` provided threw an error. + case bodyPartFileSizeQueryFailedWithError(forURL: URL, error: Error) + /// An `InputStream` could not be created for the provided `fileURL`. + case bodyPartInputStreamCreationFailed(for: URL) + /// An `OutputStream` could not be created when attempting to write the encoded data to disk. + case outputStreamCreationFailed(for: URL) + /// The encoded body data could not be written to disk because a file already exists at the provided `fileURL`. + case outputStreamFileAlreadyExists(at: URL) + /// The `fileURL` provided for writing the encoded body data to disk is not a file `URL`. + case outputStreamURLInvalid(url: URL) + /// The attempt to write the encoded body data to disk failed with an underlying error. + case outputStreamWriteFailed(error: Error) + /// The attempt to read an encoded body part `InputStream` failed with underlying system error. + case inputStreamReadFailed(error: Error) + } + + /// Represents unexpected input stream length that occur when encoding the `MultipartFormData`. Instances will be + /// embedded within an `AFError.multipartEncodingFailed` `.inputStreamReadFailed` case. + public struct UnexpectedInputStreamLength: Error { + /// The expected byte count to read. + public var bytesExpected: UInt64 + /// The actual byte count read. + public var bytesRead: UInt64 + } + + /// The underlying reason the `.parameterEncodingFailed` error occurred. + public enum ParameterEncodingFailureReason { + /// The `URLRequest` did not have a `URL` to encode. + case missingURL + /// JSON serialization failed with an underlying system error during the encoding process. + case jsonEncodingFailed(error: Error) + /// Custom parameter encoding failed due to the associated `Error`. + case customEncodingFailed(error: Error) + } + + /// The underlying reason the `.parameterEncoderFailed` error occurred. + public enum ParameterEncoderFailureReason { + /// Possible missing components. + public enum RequiredComponent { + /// The `URL` was missing or unable to be extracted from the passed `URLRequest` or during encoding. + case url + /// The `HTTPMethod` could not be extracted from the passed `URLRequest`. + case httpMethod(rawValue: String) + } + + /// A `RequiredComponent` was missing during encoding. + case missingRequiredComponent(RequiredComponent) + /// The underlying encoder failed with the associated error. + case encoderFailed(error: Error) + } + + /// The underlying reason the `.responseValidationFailed` error occurred. + public enum ResponseValidationFailureReason { + /// The data file containing the server response did not exist. + case dataFileNil + /// The data file containing the server response at the associated `URL` could not be read. + case dataFileReadFailed(at: URL) + /// The response did not contain a `Content-Type` and the `acceptableContentTypes` provided did not contain a + /// wildcard type. + case missingContentType(acceptableContentTypes: [String]) + /// The response `Content-Type` did not match any type in the provided `acceptableContentTypes`. + case unacceptableContentType(acceptableContentTypes: [String], responseContentType: String) + /// The response status code was not acceptable. + case unacceptableStatusCode(code: Int) + /// Custom response validation failed due to the associated `Error`. + case customValidationFailed(error: Error) + } + + /// The underlying reason the response serialization error occurred. + public enum ResponseSerializationFailureReason { + /// The server response contained no data or the data was zero length. + case inputDataNilOrZeroLength + /// The file containing the server response did not exist. + case inputFileNil + /// The file containing the server response could not be read from the associated `URL`. + case inputFileReadFailed(at: URL) + /// String serialization failed using the provided `String.Encoding`. + case stringSerializationFailed(encoding: String.Encoding) + /// JSON serialization failed with an underlying system error. + case jsonSerializationFailed(error: Error) + /// A `DataDecoder` failed to decode the response due to the associated `Error`. + case decodingFailed(error: Error) + /// A custom response serializer failed due to the associated `Error`. + case customSerializationFailed(error: Error) + /// Generic serialization failed for an empty response that wasn't type `Empty` but instead the associated type. + case invalidEmptyResponse(type: String) + } + + #if !(os(Linux) || os(Windows)) + /// Underlying reason a server trust evaluation error occurred. + public enum ServerTrustFailureReason { + /// The output of a server trust evaluation. + public struct Output { + /// The host for which the evaluation was performed. + public let host: String + /// The `SecTrust` value which was evaluated. + public let trust: SecTrust + /// The `OSStatus` of evaluation operation. + public let status: OSStatus + /// The result of the evaluation operation. + public let result: SecTrustResultType + + /// Creates an `Output` value from the provided values. + init(_ host: String, _ trust: SecTrust, _ status: OSStatus, _ result: SecTrustResultType) { + self.host = host + self.trust = trust + self.status = status + self.result = result + } + } + + /// No `ServerTrustEvaluator` was found for the associated host. + case noRequiredEvaluator(host: String) + /// No certificates were found with which to perform the trust evaluation. + case noCertificatesFound + /// No public keys were found with which to perform the trust evaluation. + case noPublicKeysFound + /// During evaluation, application of the associated `SecPolicy` failed. + case policyApplicationFailed(trust: SecTrust, policy: SecPolicy, status: OSStatus) + /// During evaluation, setting the associated anchor certificates failed. + case settingAnchorCertificatesFailed(status: OSStatus, certificates: [SecCertificate]) + /// During evaluation, creation of the revocation policy failed. + case revocationPolicyCreationFailed + /// `SecTrust` evaluation failed with the associated `Error`, if one was produced. + case trustEvaluationFailed(error: Error?) + /// Default evaluation failed with the associated `Output`. + case defaultEvaluationFailed(output: Output) + /// Host validation failed with the associated `Output`. + case hostValidationFailed(output: Output) + /// Revocation check failed with the associated `Output` and options. + case revocationCheckFailed(output: Output, options: RevocationTrustEvaluator.Options) + /// Certificate pinning failed. + case certificatePinningFailed(host: String, trust: SecTrust, pinnedCertificates: [SecCertificate], serverCertificates: [SecCertificate]) + /// Public key pinning failed. + case publicKeyPinningFailed(host: String, trust: SecTrust, pinnedKeys: [SecKey], serverKeys: [SecKey]) + /// Custom server trust evaluation failed due to the associated `Error`. + case customEvaluationFailed(error: Error) + } + #endif + + /// The underlying reason the `.urlRequestValidationFailed` + public enum URLRequestValidationFailureReason { + /// URLRequest with GET method had body data. + case bodyDataInGETRequest(Data) + } + + /// `UploadableConvertible` threw an error in `createUploadable()`. + case createUploadableFailed(error: Error) + /// `URLRequestConvertible` threw an error in `asURLRequest()`. + case createURLRequestFailed(error: Error) + /// `SessionDelegate` threw an error while attempting to move downloaded file to destination URL. + case downloadedFileMoveFailed(error: Error, source: URL, destination: URL) + /// `Request` was explicitly cancelled. + case explicitlyCancelled + /// `URLConvertible` type failed to create a valid `URL`. + case invalidURL(url: URLConvertible) + /// Multipart form encoding failed. + case multipartEncodingFailed(reason: MultipartEncodingFailureReason) + /// `ParameterEncoding` threw an error during the encoding process. + case parameterEncodingFailed(reason: ParameterEncodingFailureReason) + /// `ParameterEncoder` threw an error while running the encoder. + case parameterEncoderFailed(reason: ParameterEncoderFailureReason) + /// `RequestAdapter` threw an error during adaptation. + case requestAdaptationFailed(error: Error) + /// `RequestRetrier` threw an error during the request retry process. + case requestRetryFailed(retryError: Error, originalError: Error) + /// Response validation failed. + case responseValidationFailed(reason: ResponseValidationFailureReason) + /// Response serialization failed. + case responseSerializationFailed(reason: ResponseSerializationFailureReason) + #if !(os(Linux) || os(Windows)) + /// `ServerTrustEvaluating` instance threw an error during trust evaluation. + case serverTrustEvaluationFailed(reason: ServerTrustFailureReason) + #endif + /// `Session` which issued the `Request` was deinitialized, most likely because its reference went out of scope. + case sessionDeinitialized + /// `Session` was explicitly invalidated, possibly with the `Error` produced by the underlying `URLSession`. + case sessionInvalidated(error: Error?) + /// `URLSessionTask` completed with error. + case sessionTaskFailed(error: Error) + /// `URLRequest` failed validation. + case urlRequestValidationFailed(reason: URLRequestValidationFailureReason) +} + +extension Error { + /// Returns the instance cast as an `AFError`. + public var asAFError: AFError? { + self as? AFError + } + + /// Returns the instance cast as an `AFError`. If casting fails, a `fatalError` with the specified `message` is thrown. + public func asAFError(orFailWith message: @autoclosure () -> String, file: StaticString = #file, line: UInt = #line) -> AFError { + guard let afError = self as? AFError else { + fatalError(message(), file: file, line: line) + } + return afError + } + + /// Casts the instance as `AFError` or returns `defaultAFError` + func asAFError(or defaultAFError: @autoclosure () -> AFError) -> AFError { + self as? AFError ?? defaultAFError() + } +} + +// MARK: - Error Booleans + +extension AFError { + /// Returns whether the instance is `.sessionDeinitialized`. + public var isSessionDeinitializedError: Bool { + if case .sessionDeinitialized = self { return true } + return false + } + + /// Returns whether the instance is `.sessionInvalidated`. + public var isSessionInvalidatedError: Bool { + if case .sessionInvalidated = self { return true } + return false + } + + /// Returns whether the instance is `.explicitlyCancelled`. + public var isExplicitlyCancelledError: Bool { + if case .explicitlyCancelled = self { return true } + return false + } + + /// Returns whether the instance is `.invalidURL`. + public var isInvalidURLError: Bool { + if case .invalidURL = self { return true } + return false + } + + /// Returns whether the instance is `.parameterEncodingFailed`. 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 instance is `.parameterEncoderFailed`. When `true`, the `underlyingError` property will + /// contain the associated value. + public var isParameterEncoderError: Bool { + if case .parameterEncoderFailed = self { return true } + return false + } + + /// Returns whether the instance is `.multipartEncodingFailed`. 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 instance is `.requestAdaptationFailed`. When `true`, the `underlyingError` property will + /// contain the associated value. + public var isRequestAdaptationError: Bool { + if case .requestAdaptationFailed = self { return true } + return false + } + + /// Returns whether the instance is `.responseValidationFailed`. When `true`, the `acceptableContentTypes`, + /// `responseContentType`, `responseCode`, and `underlyingError` properties will contain the associated values. + public var isResponseValidationError: Bool { + if case .responseValidationFailed = self { return true } + return false + } + + /// Returns whether the instance is `.responseSerializationFailed`. When `true`, the `failedStringEncoding` and + /// `underlyingError` properties will contain the associated values. + public var isResponseSerializationError: Bool { + if case .responseSerializationFailed = self { return true } + return false + } + + #if !(os(Linux) || os(Windows)) + /// Returns whether the instance is `.serverTrustEvaluationFailed`. When `true`, the `underlyingError` property will + /// contain the associated value. + public var isServerTrustEvaluationError: Bool { + if case .serverTrustEvaluationFailed = self { return true } + return false + } + #endif + + /// Returns whether the instance is `requestRetryFailed`. When `true`, the `underlyingError` property will + /// contain the associated value. + public var isRequestRetryError: Bool { + if case .requestRetryFailed = self { return true } + return false + } + + /// Returns whether the instance is `createUploadableFailed`. When `true`, the `underlyingError` property will + /// contain the associated value. + public var isCreateUploadableError: Bool { + if case .createUploadableFailed = self { return true } + return false + } + + /// Returns whether the instance is `createURLRequestFailed`. When `true`, the `underlyingError` property will + /// contain the associated value. + public var isCreateURLRequestError: Bool { + if case .createURLRequestFailed = self { return true } + return false + } + + /// Returns whether the instance is `downloadedFileMoveFailed`. When `true`, the `destination` and `underlyingError` properties will + /// contain the associated values. + public var isDownloadedFileMoveError: Bool { + if case .downloadedFileMoveFailed = self { return true } + return false + } + + /// Returns whether the instance is `createURLRequestFailed`. When `true`, the `underlyingError` property will + /// contain the associated value. + public var isSessionTaskError: Bool { + if case .sessionTaskFailed = self { return true } + return false + } +} + +// MARK: - Convenience Properties + +extension AFError { + /// The `URLConvertible` associated with the error. + public var urlConvertible: URLConvertible? { + guard case let .invalidURL(url) = self else { return nil } + return url + } + + /// The `URL` associated with the error. + public var url: URL? { + guard case let .multipartEncodingFailed(reason) = self else { return nil } + return reason.url + } + + /// The underlying `Error` responsible for generating the failure associated with `.sessionInvalidated`, + /// `.parameterEncodingFailed`, `.parameterEncoderFailed`, `.multipartEncodingFailed`, `.requestAdaptationFailed`, + /// `.responseSerializationFailed`, `.requestRetryFailed` errors. + public var underlyingError: Error? { + switch self { + case let .multipartEncodingFailed(reason): + return reason.underlyingError + case let .parameterEncodingFailed(reason): + return reason.underlyingError + case let .parameterEncoderFailed(reason): + return reason.underlyingError + case let .requestAdaptationFailed(error): + return error + case let .requestRetryFailed(retryError, _): + return retryError + case let .responseValidationFailed(reason): + return reason.underlyingError + case let .responseSerializationFailed(reason): + return reason.underlyingError + #if !(os(Linux) || os(Windows)) + case let .serverTrustEvaluationFailed(reason): + return reason.underlyingError + #endif + case let .sessionInvalidated(error): + return error + case let .createUploadableFailed(error): + return error + case let .createURLRequestFailed(error): + return error + case let .downloadedFileMoveFailed(error, _, _): + return error + case let .sessionTaskFailed(error): + return error + case .explicitlyCancelled, + .invalidURL, + .sessionDeinitialized, + .urlRequestValidationFailed: + return nil + } + } + + /// The acceptable `Content-Type`s of a `.responseValidationFailed` error. + public var acceptableContentTypes: [String]? { + guard case let .responseValidationFailed(reason) = self else { return nil } + return reason.acceptableContentTypes + } + + /// The response `Content-Type` of a `.responseValidationFailed` error. + public var responseContentType: String? { + guard case let .responseValidationFailed(reason) = self else { return nil } + return reason.responseContentType + } + + /// The response code of a `.responseValidationFailed` error. + public var responseCode: Int? { + guard case let .responseValidationFailed(reason) = self else { return nil } + return reason.responseCode + } + + /// The `String.Encoding` associated with a failed `.stringResponse()` call. + public var failedStringEncoding: String.Encoding? { + guard case let .responseSerializationFailed(reason) = self else { return nil } + return reason.failedStringEncoding + } + + /// The `source` URL of a `.downloadedFileMoveFailed` error. + public var sourceURL: URL? { + guard case let .downloadedFileMoveFailed(_, source, _) = self else { return nil } + return source + } + + /// The `destination` URL of a `.downloadedFileMoveFailed` error. + public var destinationURL: URL? { + guard case let .downloadedFileMoveFailed(_, _, destination) = self else { return nil } + return destination + } + + #if !(os(Linux) || os(Windows)) + /// The download resume data of any underlying network error. Only produced by `DownloadRequest`s. + public var downloadResumeData: Data? { + (underlyingError as? URLError)?.userInfo[NSURLSessionDownloadTaskResumeData] as? Data + } + #endif +} + +extension AFError.ParameterEncodingFailureReason { + var underlyingError: Error? { + switch self { + case let .jsonEncodingFailed(error), + let .customEncodingFailed(error): + return error + case .missingURL: + return nil + } + } +} + +extension AFError.ParameterEncoderFailureReason { + var underlyingError: Error? { + switch self { + case let .encoderFailed(error): + return error + case .missingRequiredComponent: + return nil + } + } +} + +extension AFError.MultipartEncodingFailureReason { + var url: URL? { + switch self { + case let .bodyPartURLInvalid(url), + let .bodyPartFilenameInvalid(url), + let .bodyPartFileNotReachable(url), + let .bodyPartFileIsDirectory(url), + let .bodyPartFileSizeNotAvailable(url), + let .bodyPartInputStreamCreationFailed(url), + let .outputStreamCreationFailed(url), + let .outputStreamFileAlreadyExists(url), + let .outputStreamURLInvalid(url), + let .bodyPartFileNotReachableWithError(url, _), + let .bodyPartFileSizeQueryFailedWithError(url, _): + return url + case .outputStreamWriteFailed, + .inputStreamReadFailed: + return nil + } + } + + var underlyingError: Error? { + switch self { + case let .bodyPartFileNotReachableWithError(_, error), + let .bodyPartFileSizeQueryFailedWithError(_, error), + let .outputStreamWriteFailed(error), + let .inputStreamReadFailed(error): + return error + case .bodyPartURLInvalid, + .bodyPartFilenameInvalid, + .bodyPartFileNotReachable, + .bodyPartFileIsDirectory, + .bodyPartFileSizeNotAvailable, + .bodyPartInputStreamCreationFailed, + .outputStreamCreationFailed, + .outputStreamFileAlreadyExists, + .outputStreamURLInvalid: + return nil + } + } +} + +extension AFError.ResponseValidationFailureReason { + var acceptableContentTypes: [String]? { + switch self { + case let .missingContentType(types), + let .unacceptableContentType(types, _): + return types + case .dataFileNil, + .dataFileReadFailed, + .unacceptableStatusCode, + .customValidationFailed: + return nil + } + } + + var responseContentType: String? { + switch self { + case let .unacceptableContentType(_, responseType): + return responseType + case .dataFileNil, + .dataFileReadFailed, + .missingContentType, + .unacceptableStatusCode, + .customValidationFailed: + return nil + } + } + + var responseCode: Int? { + switch self { + case let .unacceptableStatusCode(code): + return code + case .dataFileNil, + .dataFileReadFailed, + .missingContentType, + .unacceptableContentType, + .customValidationFailed: + return nil + } + } + + var underlyingError: Error? { + switch self { + case let .customValidationFailed(error): + return error + case .dataFileNil, + .dataFileReadFailed, + .missingContentType, + .unacceptableContentType, + .unacceptableStatusCode: + return nil + } + } +} + +extension AFError.ResponseSerializationFailureReason { + var failedStringEncoding: String.Encoding? { + switch self { + case let .stringSerializationFailed(encoding): + return encoding + case .inputDataNilOrZeroLength, + .inputFileNil, + .inputFileReadFailed(_), + .jsonSerializationFailed(_), + .decodingFailed(_), + .customSerializationFailed(_), + .invalidEmptyResponse: + return nil + } + } + + var underlyingError: Error? { + switch self { + case let .jsonSerializationFailed(error), + let .decodingFailed(error), + let .customSerializationFailed(error): + return error + case .inputDataNilOrZeroLength, + .inputFileNil, + .inputFileReadFailed, + .stringSerializationFailed, + .invalidEmptyResponse: + return nil + } + } +} + +#if !(os(Linux) || os(Windows)) +extension AFError.ServerTrustFailureReason { + var output: AFError.ServerTrustFailureReason.Output? { + switch self { + case let .defaultEvaluationFailed(output), + let .hostValidationFailed(output), + let .revocationCheckFailed(output, _): + return output + case .noRequiredEvaluator, + .noCertificatesFound, + .noPublicKeysFound, + .policyApplicationFailed, + .settingAnchorCertificatesFailed, + .revocationPolicyCreationFailed, + .trustEvaluationFailed, + .certificatePinningFailed, + .publicKeyPinningFailed, + .customEvaluationFailed: + return nil + } + } + + var underlyingError: Error? { + switch self { + case let .customEvaluationFailed(error): + return error + case let .trustEvaluationFailed(error): + return error + case .noRequiredEvaluator, + .noCertificatesFound, + .noPublicKeysFound, + .policyApplicationFailed, + .settingAnchorCertificatesFailed, + .revocationPolicyCreationFailed, + .defaultEvaluationFailed, + .hostValidationFailed, + .revocationCheckFailed, + .certificatePinningFailed, + .publicKeyPinningFailed: + return nil + } + } +} +#endif + +// MARK: - Error Descriptions + +extension AFError: LocalizedError { + public var errorDescription: String? { + switch self { + case .explicitlyCancelled: + return "Request explicitly cancelled." + case let .invalidURL(url): + return "URL is not valid: \(url)" + case let .parameterEncodingFailed(reason): + return reason.localizedDescription + case let .parameterEncoderFailed(reason): + return reason.localizedDescription + case let .multipartEncodingFailed(reason): + return reason.localizedDescription + case let .requestAdaptationFailed(error): + return "Request adaption failed with error: \(error.localizedDescription)" + case let .responseValidationFailed(reason): + return reason.localizedDescription + case let .responseSerializationFailed(reason): + return reason.localizedDescription + case let .requestRetryFailed(retryError, originalError): + return """ + Request retry failed with retry error: \(retryError.localizedDescription), \ + original error: \(originalError.localizedDescription) + """ + case .sessionDeinitialized: + return """ + Session was invalidated without error, so it was likely deinitialized unexpectedly. \ + Be sure to retain a reference to your Session for the duration of your requests. + """ + case let .sessionInvalidated(error): + return "Session was invalidated with error: \(error?.localizedDescription ?? "No description.")" + #if !(os(Linux) || os(Windows)) + case let .serverTrustEvaluationFailed(reason): + return "Server trust evaluation failed due to reason: \(reason.localizedDescription)" + #endif + case let .urlRequestValidationFailed(reason): + return "URLRequest validation failed due to reason: \(reason.localizedDescription)" + case let .createUploadableFailed(error): + return "Uploadable creation failed with error: \(error.localizedDescription)" + case let .createURLRequestFailed(error): + return "URLRequest creation failed with error: \(error.localizedDescription)" + case let .downloadedFileMoveFailed(error, source, destination): + return "Moving downloaded file from: \(source) to: \(destination) failed with error: \(error.localizedDescription)" + case let .sessionTaskFailed(error): + return "URLSessionTask failed with error: \(error.localizedDescription)" + } + } +} + +extension AFError.ParameterEncodingFailureReason { + var localizedDescription: String { + switch self { + case .missingURL: + return "URL request to encode was missing a URL" + case let .jsonEncodingFailed(error): + return "JSON could not be encoded because of error:\n\(error.localizedDescription)" + case let .customEncodingFailed(error): + return "Custom parameter encoder failed with error: \(error.localizedDescription)" + } + } +} + +extension AFError.ParameterEncoderFailureReason { + var localizedDescription: String { + switch self { + case let .missingRequiredComponent(component): + return "Encoding failed due to a missing request component: \(component)" + case let .encoderFailed(error): + return "The underlying encoder failed with the error: \(error)" + } + } +} + +extension AFError.MultipartEncodingFailureReason { + var localizedDescription: String { + switch self { + case let .bodyPartURLInvalid(url): + return "The URL provided is not a file URL: \(url)" + case let .bodyPartFilenameInvalid(url): + return "The URL provided does not have a valid filename: \(url)" + case let .bodyPartFileNotReachable(url): + return "The URL provided is not reachable: \(url)" + case let .bodyPartFileNotReachableWithError(url, error): + return """ + The system returned an error while checking the provided URL for reachability. + URL: \(url) + Error: \(error) + """ + case let .bodyPartFileIsDirectory(url): + return "The URL provided is a directory: \(url)" + case let .bodyPartFileSizeNotAvailable(url): + return "Could not fetch the file size from the provided URL: \(url)" + case let .bodyPartFileSizeQueryFailedWithError(url, error): + return """ + The system returned an error while attempting to fetch the file size from the provided URL. + URL: \(url) + Error: \(error) + """ + case let .bodyPartInputStreamCreationFailed(url): + return "Failed to create an InputStream for the provided URL: \(url)" + case let .outputStreamCreationFailed(url): + return "Failed to create an OutputStream for URL: \(url)" + case let .outputStreamFileAlreadyExists(url): + return "A file already exists at the provided URL: \(url)" + case let .outputStreamURLInvalid(url): + return "The provided OutputStream URL is invalid: \(url)" + case let .outputStreamWriteFailed(error): + return "OutputStream write failed with error: \(error)" + case let .inputStreamReadFailed(error): + return "InputStream read failed with error: \(error)" + } + } +} + +extension AFError.ResponseSerializationFailureReason { + var localizedDescription: String { + switch self { + 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 let .inputFileReadFailed(url): + return "Response could not be serialized, input file could not be read: \(url)." + case let .stringSerializationFailed(encoding): + return "String could not be serialized with encoding: \(encoding)." + case let .jsonSerializationFailed(error): + return "JSON could not be serialized because of error:\n\(error.localizedDescription)" + case let .invalidEmptyResponse(type): + return """ + Empty response could not be serialized to type: \(type). \ + Use Empty as the expected type for such responses. + """ + case let .decodingFailed(error): + return "Response could not be decoded because of error:\n\(error.localizedDescription)" + case let .customSerializationFailed(error): + return "Custom response serializer failed with 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 let .dataFileReadFailed(url): + return "Response could not be validated, data file could not be read: \(url)." + case let .missingContentType(types): + return """ + Response Content-Type was missing and acceptable content types \ + (\(types.joined(separator: ","))) do not match "*/*". + """ + case let .unacceptableContentType(acceptableTypes, responseType): + return """ + Response Content-Type "\(responseType)" does not match any acceptable types: \ + \(acceptableTypes.joined(separator: ",")). + """ + case let .unacceptableStatusCode(code): + return "Response status code was unacceptable: \(code)." + case let .customValidationFailed(error): + return "Custom response validation failed with error: \(error.localizedDescription)" + } + } +} + +#if !(os(Linux) || os(Windows)) +extension AFError.ServerTrustFailureReason { + var localizedDescription: String { + switch self { + case let .noRequiredEvaluator(host): + return "A ServerTrustEvaluating value is required for host \(host) but none was found." + case .noCertificatesFound: + return "No certificates were found or provided for evaluation." + case .noPublicKeysFound: + return "No public keys were found or provided for evaluation." + case .policyApplicationFailed: + return "Attempting to set a SecPolicy failed." + case .settingAnchorCertificatesFailed: + return "Attempting to set the provided certificates as anchor certificates failed." + case .revocationPolicyCreationFailed: + return "Attempting to create a revocation policy failed." + case let .trustEvaluationFailed(error): + return "SecTrust evaluation failed with error: \(error?.localizedDescription ?? "None")" + case let .defaultEvaluationFailed(output): + return "Default evaluation failed for host \(output.host)." + case let .hostValidationFailed(output): + return "Host validation failed for host \(output.host)." + case let .revocationCheckFailed(output, _): + return "Revocation check failed for host \(output.host)." + case let .certificatePinningFailed(host, _, _, _): + return "Certificate pinning failed for host \(host)." + case let .publicKeyPinningFailed(host, _, _, _): + return "Public key pinning failed for host \(host)." + case let .customEvaluationFailed(error): + return "Custom trust evaluation failed with error: \(error.localizedDescription)" + } + } +} +#endif + +extension AFError.URLRequestValidationFailureReason { + var localizedDescription: String { + switch self { + case let .bodyDataInGETRequest(data): + return """ + Invalid URLRequest: Requests with GET method cannot have body data: + \(String(decoding: data, as: UTF8.self)) + """ + } + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/Alamofire.swift b/Instagram-Clone/Pods/Alamofire/Source/Alamofire.swift new file mode 100644 index 0000000..0d3f5dc --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/Alamofire.swift @@ -0,0 +1,35 @@ +// +// Alamofire.swift +// +// Copyright (c) 2014-2021 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 +#if canImport(FoundationNetworking) +@_exported import FoundationNetworking +#endif + +/// Reference to `Session.default` for quick bootstrapping and examples. +public let AF = Session.default + +/// Current Alamofire version. Necessary since SPM doesn't use dynamic libraries. Plus this will be more accurate. +let version = "5.5.0" diff --git a/Instagram-Clone/Pods/Alamofire/Source/AlamofireExtended.swift b/Instagram-Clone/Pods/Alamofire/Source/AlamofireExtended.swift new file mode 100644 index 0000000..280c6de --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/AlamofireExtended.swift @@ -0,0 +1,61 @@ +// +// AlamofireExtended.swift +// +// Copyright (c) 2019 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. +// + +/// Type that acts as a generic extension point for all `AlamofireExtended` types. +public struct AlamofireExtension { + /// Stores the type or meta-type of any extended type. + public private(set) var type: ExtendedType + + /// Create an instance from the provided value. + /// + /// - Parameter type: Instance being extended. + public init(_ type: ExtendedType) { + self.type = type + } +} + +/// Protocol describing the `af` extension points for Alamofire extended types. +public protocol AlamofireExtended { + /// Type being extended. + associatedtype ExtendedType + + /// Static Alamofire extension point. + static var af: AlamofireExtension.Type { get set } + /// Instance Alamofire extension point. + var af: AlamofireExtension { get set } +} + +extension AlamofireExtended { + /// Static Alamofire extension point. + public static var af: AlamofireExtension.Type { + get { AlamofireExtension.self } + set {} + } + + /// Instance Alamofire extension point. + public var af: AlamofireExtension { + get { AlamofireExtension(self) } + set {} + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/AuthenticationInterceptor.swift b/Instagram-Clone/Pods/Alamofire/Source/AuthenticationInterceptor.swift new file mode 100644 index 0000000..c3a3f31 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/AuthenticationInterceptor.swift @@ -0,0 +1,403 @@ +// +// AuthenticationInterceptor.swift +// +// Copyright (c) 2020 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 `AuthenticationCredential` protocol can be used to authenticate `URLRequest`s. +/// +/// One common example of an `AuthenticationCredential` is an OAuth2 credential containing an access token used to +/// authenticate all requests on behalf of a user. The access token generally has an expiration window of 60 minutes +/// which will then require a refresh of the credential using the refresh token to generate a new access token. +public protocol AuthenticationCredential { + /// Whether the credential requires a refresh. This property should always return `true` when the credential is + /// expired. It is also wise to consider returning `true` when the credential will expire in several seconds or + /// minutes depending on the expiration window of the credential. + /// + /// For example, if the credential is valid for 60 minutes, then it would be wise to return `true` when the + /// credential is only valid for 5 minutes or less. That ensures the credential will not expire as it is passed + /// around backend services. + var requiresRefresh: Bool { get } +} + +// MARK: - + +/// Types adopting the `Authenticator` protocol can be used to authenticate `URLRequest`s with an +/// `AuthenticationCredential` as well as refresh the `AuthenticationCredential` when required. +public protocol Authenticator: AnyObject { + /// The type of credential associated with the `Authenticator` instance. + associatedtype Credential: AuthenticationCredential + + /// Applies the `Credential` to the `URLRequest`. + /// + /// In the case of OAuth2, the access token of the `Credential` would be added to the `URLRequest` as a Bearer + /// token to the `Authorization` header. + /// + /// - Parameters: + /// - credential: The `Credential`. + /// - urlRequest: The `URLRequest`. + func apply(_ credential: Credential, to urlRequest: inout URLRequest) + + /// Refreshes the `Credential` and executes the `completion` closure with the `Result` once complete. + /// + /// Refresh can be called in one of two ways. It can be called before the `Request` is actually executed due to + /// a `requiresRefresh` returning `true` during the adapt portion of the `Request` creation process. It can also + /// be triggered by a failed `Request` where the authentication server denied access due to an expired or + /// invalidated access token. + /// + /// In the case of OAuth2, this method would use the refresh token of the `Credential` to generate a new + /// `Credential` using the authentication service. Once complete, the `completion` closure should be called with + /// the new `Credential`, or the error that occurred. + /// + /// In general, if the refresh call fails with certain status codes from the authentication server (commonly a 401), + /// the refresh token in the `Credential` can no longer be used to generate a valid `Credential`. In these cases, + /// you will need to reauthenticate the user with their username / password. + /// + /// Please note, these are just general examples of common use cases. They are not meant to solve your specific + /// authentication server challenges. Please work with your authentication server team to ensure your + /// `Authenticator` logic matches their expectations. + /// + /// - Parameters: + /// - credential: The `Credential` to refresh. + /// - session: The `Session` requiring the refresh. + /// - completion: The closure to be executed once the refresh is complete. + func refresh(_ credential: Credential, for session: Session, completion: @escaping (Result) -> Void) + + /// Determines whether the `URLRequest` failed due to an authentication error based on the `HTTPURLResponse`. + /// + /// If the authentication server **CANNOT** invalidate credentials after they are issued, then simply return `false` + /// for this method. If the authentication server **CAN** invalidate credentials due to security breaches, then you + /// will need to work with your authentication server team to understand how to identify when this occurs. + /// + /// In the case of OAuth2, where an authentication server can invalidate credentials, you will need to inspect the + /// `HTTPURLResponse` or possibly the `Error` for when this occurs. This is commonly handled by the authentication + /// server returning a 401 status code and some additional header to indicate an OAuth2 failure occurred. + /// + /// It is very important to understand how your authentication server works to be able to implement this correctly. + /// For example, if your authentication server returns a 401 when an OAuth2 error occurs, and your downstream + /// service also returns a 401 when you are not authorized to perform that operation, how do you know which layer + /// of the backend returned you a 401? You do not want to trigger a refresh unless you know your authentication + /// server is actually the layer rejecting the request. Again, work with your authentication server team to understand + /// how to identify an OAuth2 401 error vs. a downstream 401 error to avoid endless refresh loops. + /// + /// - Parameters: + /// - urlRequest: The `URLRequest`. + /// - response: The `HTTPURLResponse`. + /// - error: The `Error`. + /// + /// - Returns: `true` if the `URLRequest` failed due to an authentication error, `false` otherwise. + func didRequest(_ urlRequest: URLRequest, with response: HTTPURLResponse, failDueToAuthenticationError error: Error) -> Bool + + /// Determines whether the `URLRequest` is authenticated with the `Credential`. + /// + /// If the authentication server **CANNOT** invalidate credentials after they are issued, then simply return `true` + /// for this method. If the authentication server **CAN** invalidate credentials due to security breaches, then + /// read on. + /// + /// When an authentication server can invalidate credentials, it means that you may have a non-expired credential + /// that appears to be valid, but will be rejected by the authentication server when used. Generally when this + /// happens, a number of requests are all sent when the application is foregrounded, and all of them will be + /// rejected by the authentication server in the order they are received. The first failed request will trigger a + /// refresh internally, which will update the credential, and then retry all the queued requests with the new + /// credential. However, it is possible that some of the original requests will not return from the authentication + /// server until the refresh has completed. This is where this method comes in. + /// + /// When the authentication server rejects a credential, we need to check to make sure we haven't refreshed the + /// credential while the request was in flight. If it has already refreshed, then we don't need to trigger an + /// additional refresh. If it hasn't refreshed, then we need to refresh. + /// + /// Now that it is understood how the result of this method is used in the refresh lifecyle, let's walk through how + /// to implement it. You should return `true` in this method if the `URLRequest` is authenticated in a way that + /// matches the values in the `Credential`. In the case of OAuth2, this would mean that the Bearer token in the + /// `Authorization` header of the `URLRequest` matches the access token in the `Credential`. If it matches, then we + /// know the `Credential` was used to authenticate the `URLRequest` and should return `true`. If the Bearer token + /// did not match the access token, then you should return `false`. + /// + /// - Parameters: + /// - urlRequest: The `URLRequest`. + /// - credential: The `Credential`. + /// + /// - Returns: `true` if the `URLRequest` is authenticated with the `Credential`, `false` otherwise. + func isRequest(_ urlRequest: URLRequest, authenticatedWith credential: Credential) -> Bool +} + +// MARK: - + +/// Represents various authentication failures that occur when using the `AuthenticationInterceptor`. All errors are +/// still vended from Alamofire as `AFError` types. The `AuthenticationError` instances will be embedded within +/// `AFError` `.requestAdaptationFailed` or `.requestRetryFailed` cases. +public enum AuthenticationError: Error { + /// The credential was missing so the request could not be authenticated. + case missingCredential + /// The credential was refreshed too many times within the `RefreshWindow`. + case excessiveRefresh +} + +// MARK: - + +/// The `AuthenticationInterceptor` class manages the queuing and threading complexity of authenticating requests. +/// It relies on an `Authenticator` type to handle the actual `URLRequest` authentication and `Credential` refresh. +public class AuthenticationInterceptor: RequestInterceptor where AuthenticatorType: Authenticator { + // MARK: Typealiases + + /// Type of credential used to authenticate requests. + public typealias Credential = AuthenticatorType.Credential + + // MARK: Helper Types + + /// Type that defines a time window used to identify excessive refresh calls. When enabled, prior to executing a + /// refresh, the `AuthenticationInterceptor` compares the timestamp history of previous refresh calls against the + /// `RefreshWindow`. If more refreshes have occurred within the refresh window than allowed, the refresh is + /// cancelled and an `AuthorizationError.excessiveRefresh` error is thrown. + public struct RefreshWindow { + /// `TimeInterval` defining the duration of the time window before the current time in which the number of + /// refresh attempts is compared against `maximumAttempts`. For example, if `interval` is 30 seconds, then the + /// `RefreshWindow` represents the past 30 seconds. If more attempts occurred in the past 30 seconds than + /// `maximumAttempts`, an `.excessiveRefresh` error will be thrown. + public let interval: TimeInterval + + /// Total refresh attempts allowed within `interval` before throwing an `.excessiveRefresh` error. + public let maximumAttempts: Int + + /// Creates a `RefreshWindow` instance from the specified `interval` and `maximumAttempts`. + /// + /// - Parameters: + /// - interval: `TimeInterval` defining the duration of the time window before the current time. + /// - maximumAttempts: The maximum attempts allowed within the `TimeInterval`. + public init(interval: TimeInterval = 30.0, maximumAttempts: Int = 5) { + self.interval = interval + self.maximumAttempts = maximumAttempts + } + } + + private struct AdaptOperation { + let urlRequest: URLRequest + let session: Session + let completion: (Result) -> Void + } + + private enum AdaptResult { + case adapt(Credential) + case doNotAdapt(AuthenticationError) + case adaptDeferred + } + + private struct MutableState { + var credential: Credential? + + var isRefreshing = false + var refreshTimestamps: [TimeInterval] = [] + var refreshWindow: RefreshWindow? + + var adaptOperations: [AdaptOperation] = [] + var requestsToRetry: [(RetryResult) -> Void] = [] + } + + // MARK: Properties + + /// The `Credential` used to authenticate requests. + public var credential: Credential? { + get { $mutableState.credential } + set { $mutableState.credential = newValue } + } + + let authenticator: AuthenticatorType + let queue = DispatchQueue(label: "org.alamofire.authentication.inspector") + + @Protected + private var mutableState: MutableState + + // MARK: Initialization + + /// Creates an `AuthenticationInterceptor` instance from the specified parameters. + /// + /// A `nil` `RefreshWindow` will result in the `AuthenticationInterceptor` not checking for excessive refresh calls. + /// It is recommended to always use a `RefreshWindow` to avoid endless refresh cycles. + /// + /// - Parameters: + /// - authenticator: The `Authenticator` type. + /// - credential: The `Credential` if it exists. `nil` by default. + /// - refreshWindow: The `RefreshWindow` used to identify excessive refresh calls. `RefreshWindow()` by default. + public init(authenticator: AuthenticatorType, + credential: Credential? = nil, + refreshWindow: RefreshWindow? = RefreshWindow()) { + self.authenticator = authenticator + mutableState = MutableState(credential: credential, refreshWindow: refreshWindow) + } + + // MARK: Adapt + + public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { + let adaptResult: AdaptResult = $mutableState.write { mutableState in + // Queue the adapt operation if a refresh is already in place. + guard !mutableState.isRefreshing else { + let operation = AdaptOperation(urlRequest: urlRequest, session: session, completion: completion) + mutableState.adaptOperations.append(operation) + return .adaptDeferred + } + + // Throw missing credential error is the credential is missing. + guard let credential = mutableState.credential else { + let error = AuthenticationError.missingCredential + return .doNotAdapt(error) + } + + // Queue the adapt operation and trigger refresh operation if credential requires refresh. + guard !credential.requiresRefresh else { + let operation = AdaptOperation(urlRequest: urlRequest, session: session, completion: completion) + mutableState.adaptOperations.append(operation) + refresh(credential, for: session, insideLock: &mutableState) + return .adaptDeferred + } + + return .adapt(credential) + } + + switch adaptResult { + case let .adapt(credential): + var authenticatedRequest = urlRequest + authenticator.apply(credential, to: &authenticatedRequest) + completion(.success(authenticatedRequest)) + + case let .doNotAdapt(adaptError): + completion(.failure(adaptError)) + + case .adaptDeferred: + // No-op: adapt operation captured during refresh. + break + } + } + + // MARK: Retry + + public func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) { + // Do not attempt retry if there was not an original request and response from the server. + guard let urlRequest = request.request, let response = request.response else { + completion(.doNotRetry) + return + } + + // Do not attempt retry unless the `Authenticator` verifies failure was due to authentication error (i.e. 401 status code). + guard authenticator.didRequest(urlRequest, with: response, failDueToAuthenticationError: error) else { + completion(.doNotRetry) + return + } + + // Do not attempt retry if there is no credential. + guard let credential = credential else { + let error = AuthenticationError.missingCredential + completion(.doNotRetryWithError(error)) + return + } + + // Retry the request if the `Authenticator` verifies it was authenticated with a previous credential. + guard authenticator.isRequest(urlRequest, authenticatedWith: credential) else { + completion(.retry) + return + } + + $mutableState.write { mutableState in + mutableState.requestsToRetry.append(completion) + + guard !mutableState.isRefreshing else { return } + + refresh(credential, for: session, insideLock: &mutableState) + } + } + + // MARK: Refresh + + private func refresh(_ credential: Credential, for session: Session, insideLock mutableState: inout MutableState) { + guard !isRefreshExcessive(insideLock: &mutableState) else { + let error = AuthenticationError.excessiveRefresh + handleRefreshFailure(error, insideLock: &mutableState) + return + } + + mutableState.refreshTimestamps.append(ProcessInfo.processInfo.systemUptime) + mutableState.isRefreshing = true + + // Dispatch to queue to hop out of the lock in case authenticator.refresh is implemented synchronously. + queue.async { + self.authenticator.refresh(credential, for: session) { result in + self.$mutableState.write { mutableState in + switch result { + case let .success(credential): + self.handleRefreshSuccess(credential, insideLock: &mutableState) + case let .failure(error): + self.handleRefreshFailure(error, insideLock: &mutableState) + } + } + } + } + } + + private func isRefreshExcessive(insideLock mutableState: inout MutableState) -> Bool { + guard let refreshWindow = mutableState.refreshWindow else { return false } + + let refreshWindowMin = ProcessInfo.processInfo.systemUptime - refreshWindow.interval + + let refreshAttemptsWithinWindow = mutableState.refreshTimestamps.reduce(into: 0) { attempts, refreshTimestamp in + guard refreshWindowMin <= refreshTimestamp else { return } + attempts += 1 + } + + let isRefreshExcessive = refreshAttemptsWithinWindow >= refreshWindow.maximumAttempts + + return isRefreshExcessive + } + + private func handleRefreshSuccess(_ credential: Credential, insideLock mutableState: inout MutableState) { + mutableState.credential = credential + + let adaptOperations = mutableState.adaptOperations + let requestsToRetry = mutableState.requestsToRetry + + mutableState.adaptOperations.removeAll() + mutableState.requestsToRetry.removeAll() + + mutableState.isRefreshing = false + + // Dispatch to queue to hop out of the mutable state lock + queue.async { + adaptOperations.forEach { self.adapt($0.urlRequest, for: $0.session, completion: $0.completion) } + requestsToRetry.forEach { $0(.retry) } + } + } + + private func handleRefreshFailure(_ error: Error, insideLock mutableState: inout MutableState) { + let adaptOperations = mutableState.adaptOperations + let requestsToRetry = mutableState.requestsToRetry + + mutableState.adaptOperations.removeAll() + mutableState.requestsToRetry.removeAll() + + mutableState.isRefreshing = false + + // Dispatch to queue to hop out of the mutable state lock + queue.async { + adaptOperations.forEach { $0.completion(.failure(error)) } + requestsToRetry.forEach { $0(.doNotRetryWithError(error)) } + } + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/CachedResponseHandler.swift b/Instagram-Clone/Pods/Alamofire/Source/CachedResponseHandler.swift new file mode 100644 index 0000000..e7d0060 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/CachedResponseHandler.swift @@ -0,0 +1,109 @@ +// +// CachedResponseHandler.swift +// +// Copyright (c) 2019 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 handles whether the data task should store the HTTP response in the cache. +public protocol CachedResponseHandler { + /// Determines whether the HTTP response should be stored in the cache. + /// + /// The `completion` closure should be passed one of three possible options: + /// + /// 1. The cached response provided by the server (this is the most common use case). + /// 2. A modified version of the cached response (you may want to modify it in some way before caching). + /// 3. A `nil` value to prevent the cached response from being stored in the cache. + /// + /// - Parameters: + /// - task: The data task whose request resulted in the cached response. + /// - response: The cached response to potentially store in the cache. + /// - completion: The closure to execute containing cached response, a modified response, or `nil`. + func dataTask(_ task: URLSessionDataTask, + willCacheResponse response: CachedURLResponse, + completion: @escaping (CachedURLResponse?) -> Void) +} + +// MARK: - + +/// `ResponseCacher` is a convenience `CachedResponseHandler` making it easy to cache, not cache, or modify a cached +/// response. +public struct ResponseCacher { + /// Defines the behavior of the `ResponseCacher` type. + public enum Behavior { + /// Stores the cached response in the cache. + case cache + /// Prevents the cached response from being stored in the cache. + case doNotCache + /// Modifies the cached response before storing it in the cache. + case modify((URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?) + } + + /// Returns a `ResponseCacher` with a `.cache` `Behavior`. + public static let cache = ResponseCacher(behavior: .cache) + /// Returns a `ResponseCacher` with a `.doNotCache` `Behavior`. + public static let doNotCache = ResponseCacher(behavior: .doNotCache) + + /// The `Behavior` of the `ResponseCacher`. + public let behavior: Behavior + + /// Creates a `ResponseCacher` instance from the `Behavior`. + /// + /// - Parameter behavior: The `Behavior`. + public init(behavior: Behavior) { + self.behavior = behavior + } +} + +extension ResponseCacher: CachedResponseHandler { + public func dataTask(_ task: URLSessionDataTask, + willCacheResponse response: CachedURLResponse, + completion: @escaping (CachedURLResponse?) -> Void) { + switch behavior { + case .cache: + completion(response) + case .doNotCache: + completion(nil) + case let .modify(closure): + let response = closure(task, response) + completion(response) + } + } +} + +#if swift(>=5.5) +extension CachedResponseHandler where Self == ResponseCacher { + /// Provides a `ResponseCacher` which caches the response, if allowed. Equivalent to `ResponseCacher.cache`. + public static var cache: ResponseCacher { .cache } + + /// Provides a `ResponseCacher` which does not cache the response. Equivalent to `ResponseCacher.doNotCache`. + public static var doNotCache: ResponseCacher { .doNotCache } + + /// Creates a `ResponseCacher` which modifies the proposed `CachedURLResponse` using the provided closure. + /// + /// - Parameter closure: Closure used to modify the `CachedURLResponse`. + /// - Returns: The `ResponseCacher`. + public static func modify(using closure: @escaping ((URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)) -> ResponseCacher { + ResponseCacher(behavior: .modify(closure)) + } +} +#endif diff --git a/Instagram-Clone/Pods/Alamofire/Source/Combine.swift b/Instagram-Clone/Pods/Alamofire/Source/Combine.swift new file mode 100644 index 0000000..066ba47 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/Combine.swift @@ -0,0 +1,655 @@ +// +// Combine.swift +// +// Copyright (c) 2020 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(iOS) && (arch(i386) || arch(arm))) || os(Windows) || os(Linux)) + +import Combine +import Dispatch +import Foundation + +// MARK: - DataRequest / UploadRequest + +/// A Combine `Publisher` that publishes the `DataResponse` of the provided `DataRequest`. +@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +public struct DataResponsePublisher: Publisher { + public typealias Output = DataResponse + public typealias Failure = Never + + private typealias Handler = (@escaping (_ response: DataResponse) -> Void) -> DataRequest + + private let request: DataRequest + private let responseHandler: Handler + + /// Creates an instance which will serialize responses using the provided `ResponseSerializer`. + /// + /// - Parameters: + /// - request: `DataRequest` for which to publish the response. + /// - queue: `DispatchQueue` on which the `DataResponse` value will be published. `.main` by default. + /// - serializer: `ResponseSerializer` used to produce the published `DataResponse`. + public init(_ request: DataRequest, queue: DispatchQueue, serializer: Serializer) + where Value == Serializer.SerializedObject { + self.request = request + responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) } + } + + /// Creates an instance which will serialize responses using the provided `DataResponseSerializerProtocol`. + /// + /// - Parameters: + /// - request: `DataRequest` for which to publish the response. + /// - queue: `DispatchQueue` on which the `DataResponse` value will be published. `.main` by default. + /// - serializer: `DataResponseSerializerProtocol` used to produce the published `DataResponse`. + public init(_ request: DataRequest, + queue: DispatchQueue, + serializer: Serializer) + where Value == Serializer.SerializedObject { + self.request = request + responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) } + } + + /// Publishes only the `Result` of the `DataResponse` value. + /// + /// - Returns: The `AnyPublisher` publishing the `Result` value. + public func result() -> AnyPublisher, Never> { + map(\.result).eraseToAnyPublisher() + } + + /// Publishes the `Result` of the `DataResponse` as a single `Value` or fail with the `AFError` instance. + /// + /// - Returns: The `AnyPublisher` publishing the stream. + public func value() -> AnyPublisher { + setFailureType(to: AFError.self).flatMap(\.result.publisher).eraseToAnyPublisher() + } + + public func receive(subscriber: S) where S: Subscriber, DataResponsePublisher.Failure == S.Failure, DataResponsePublisher.Output == S.Input { + subscriber.receive(subscription: Inner(request: request, + responseHandler: responseHandler, + downstream: subscriber)) + } + + private final class Inner: Subscription, Cancellable + where Downstream.Input == Output { + typealias Failure = Downstream.Failure + + @Protected + private var downstream: Downstream? + private let request: DataRequest + private let responseHandler: Handler + + init(request: DataRequest, responseHandler: @escaping Handler, downstream: Downstream) { + self.request = request + self.responseHandler = responseHandler + self.downstream = downstream + } + + func request(_ demand: Subscribers.Demand) { + assert(demand > 0) + + guard let downstream = downstream else { return } + + self.downstream = nil + responseHandler { response in + _ = downstream.receive(response) + downstream.receive(completion: .finished) + }.resume() + } + + func cancel() { + request.cancel() + downstream = nil + } + } +} + +@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +extension DataResponsePublisher where Value == Data? { + /// Creates an instance which publishes a `DataResponse` value without serialization. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public init(_ request: DataRequest, queue: DispatchQueue) { + self.request = request + responseHandler = { request.response(queue: queue, completionHandler: $0) } + } +} + +extension DataRequest { + /// Creates a `DataResponsePublisher` for this instance using the given `ResponseSerializer` and `DispatchQueue`. + /// + /// - Parameters: + /// - serializer: `ResponseSerializer` used to serialize response `Data`. + /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default. + /// + /// - Returns: The `DataResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishResponse(using serializer: Serializer, on queue: DispatchQueue = .main) -> DataResponsePublisher + where Serializer.SerializedObject == T { + DataResponsePublisher(self, queue: queue, serializer: serializer) + } + + /// Creates a `DataResponsePublisher` for this instance and uses a `DataResponseSerializer` to serialize the + /// response. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default. + /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()` + /// by default. + /// - emptyResponseCodes: `Set` of HTTP status codes for which empty responses are allowed. `[204, 205]` by + /// default. + /// - emptyRequestMethods: `Set` of `HTTPMethod`s for which empty responses are allowed, regardless of + /// status code. `[.head]` by default. + /// - Returns: The `DataResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishData(queue: DispatchQueue = .main, + preprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods) -> DataResponsePublisher { + publishResponse(using: DataResponseSerializer(dataPreprocessor: preprocessor, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + on: queue) + } + + /// Creates a `DataResponsePublisher` for this instance and uses a `StringResponseSerializer` to serialize the + /// response. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default. + /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()` + /// by default. + /// - encoding: `String.Encoding` to parse the response. `nil` by default, in which case the encoding + /// will be determined by the server response, falling back to the default HTTP character + /// set, `ISO-8859-1`. + /// - emptyResponseCodes: `Set` of HTTP status codes for which empty responses are allowed. `[204, 205]` by + /// default. + /// - emptyRequestMethods: `Set` of `HTTPMethod`s for which empty responses are allowed, regardless of + /// status code. `[.head]` by default. + /// + /// - Returns: The `DataResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishString(queue: DispatchQueue = .main, + preprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor, + encoding: String.Encoding? = nil, + emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = StringResponseSerializer.defaultEmptyRequestMethods) -> DataResponsePublisher { + publishResponse(using: StringResponseSerializer(dataPreprocessor: preprocessor, + encoding: encoding, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + on: queue) + } + + @_disfavoredOverload + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + @available(*, deprecated, message: "Renamed publishDecodable(type:queue:preprocessor:decoder:emptyResponseCodes:emptyRequestMethods).") + public func publishDecodable(type: T.Type = T.self, + queue: DispatchQueue = .main, + preprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, + decoder: DataDecoder = JSONDecoder(), + emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, + emptyResponseMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods) -> DataResponsePublisher { + publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor, + decoder: decoder, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyResponseMethods), + on: queue) + } + + /// Creates a `DataResponsePublisher` for this instance and uses a `DecodableResponseSerializer` to serialize the + /// response. + /// + /// - Parameters: + /// - type: `Decodable` type to which to decode response `Data`. Inferred from the context by + /// default. + /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default. + /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. + /// `PassthroughPreprocessor()` by default. + /// - decoder: `DataDecoder` instance used to decode response `Data`. `JSONDecoder()` by default. + /// - emptyResponseCodes: `Set` of HTTP status codes for which empty responses are allowed. `[204, 205]` by + /// default. + /// - emptyRequestMethods: `Set` of `HTTPMethod`s for which empty responses are allowed, regardless of + /// status code. `[.head]` by default. + /// + /// - Returns: The `DataResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishDecodable(type: T.Type = T.self, + queue: DispatchQueue = .main, + preprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, + decoder: DataDecoder = JSONDecoder(), + emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods) -> DataResponsePublisher { + publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor, + decoder: decoder, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + on: queue) + } + + /// Creates a `DataResponsePublisher` for this instance which does not serialize the response before publishing. + /// + /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default. + /// + /// - Returns: The `DataResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishUnserialized(queue: DispatchQueue = .main) -> DataResponsePublisher { + DataResponsePublisher(self, queue: queue) + } +} + +// A Combine `Publisher` that publishes a sequence of `Stream` values received by the provided `DataStreamRequest`. +@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +public struct DataStreamPublisher: Publisher { + public typealias Output = DataStreamRequest.Stream + public typealias Failure = Never + + private typealias Handler = (@escaping DataStreamRequest.Handler) -> DataStreamRequest + + private let request: DataStreamRequest + private let streamHandler: Handler + + /// Creates an instance which will serialize responses using the provided `DataStreamSerializer`. + /// + /// - Parameters: + /// - request: `DataStreamRequest` for which to publish the response. + /// - queue: `DispatchQueue` on which the `Stream` values will be published. `.main` by + /// default. + /// - serializer: `DataStreamSerializer` used to produce the published `Stream` values. + public init(_ request: DataStreamRequest, queue: DispatchQueue, serializer: Serializer) + where Value == Serializer.SerializedObject { + self.request = request + streamHandler = { request.responseStream(using: serializer, on: queue, stream: $0) } + } + + /// Publishes only the `Result` of the `DataStreamRequest.Stream`'s `Event`s. + /// + /// - Returns: The `AnyPublisher` publishing the `Result` value. + public func result() -> AnyPublisher, Never> { + compactMap { stream in + switch stream.event { + case let .stream(result): + return result + // If the stream has completed with an error, send the error value downstream as a `.failure`. + case let .complete(completion): + return completion.error.map(Result.failure) + } + } + .eraseToAnyPublisher() + } + + /// Publishes the streamed values of the `DataStreamRequest.Stream` as a sequence of `Value` or fail with the + /// `AFError` instance. + /// + /// - Returns: The `AnyPublisher` publishing the stream. + public func value() -> AnyPublisher { + result().setFailureType(to: AFError.self).flatMap(\.publisher).eraseToAnyPublisher() + } + + public func receive(subscriber: S) where S: Subscriber, DataStreamPublisher.Failure == S.Failure, DataStreamPublisher.Output == S.Input { + subscriber.receive(subscription: Inner(request: request, + streamHandler: streamHandler, + downstream: subscriber)) + } + + private final class Inner: Subscription, Cancellable + where Downstream.Input == Output { + typealias Failure = Downstream.Failure + + @Protected + private var downstream: Downstream? + private let request: DataStreamRequest + private let streamHandler: Handler + + init(request: DataStreamRequest, streamHandler: @escaping Handler, downstream: Downstream) { + self.request = request + self.streamHandler = streamHandler + self.downstream = downstream + } + + func request(_ demand: Subscribers.Demand) { + assert(demand > 0) + + guard let downstream = downstream else { return } + + self.downstream = nil + streamHandler { stream in + _ = downstream.receive(stream) + if case .complete = stream.event { + downstream.receive(completion: .finished) + } + }.resume() + } + + func cancel() { + request.cancel() + downstream = nil + } + } +} + +extension DataStreamRequest { + /// Creates a `DataStreamPublisher` for this instance using the given `DataStreamSerializer` and `DispatchQueue`. + /// + /// - Parameters: + /// - serializer: `DataStreamSerializer` used to serialize the streamed `Data`. + /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default. + /// - Returns: The `DataStreamPublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishStream(using serializer: Serializer, + on queue: DispatchQueue = .main) -> DataStreamPublisher { + DataStreamPublisher(self, queue: queue, serializer: serializer) + } + + /// Creates a `DataStreamPublisher` for this instance which uses a `PassthroughStreamSerializer` to stream `Data` + /// unserialized. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default. + /// - Returns: The `DataStreamPublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishData(queue: DispatchQueue = .main) -> DataStreamPublisher { + publishStream(using: PassthroughStreamSerializer(), on: queue) + } + + /// Creates a `DataStreamPublisher` for this instance which uses a `StringStreamSerializer` to serialize stream + /// `Data` values into `String` values. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default. + /// - Returns: The `DataStreamPublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishString(queue: DispatchQueue = .main) -> DataStreamPublisher { + publishStream(using: StringStreamSerializer(), on: queue) + } + + /// Creates a `DataStreamPublisher` for this instance which uses a `DecodableStreamSerializer` with the provided + /// parameters to serialize stream `Data` values into the provided type. + /// + /// - Parameters: + /// - type: `Decodable` type to which to decode stream `Data`. Inferred from the context by default. + /// - queue: `DispatchQueue` on which the `DataRequest.Stream` values will be published. `.main` by default. + /// - decoder: `DataDecoder` instance used to decode stream `Data`. `JSONDecoder()` by default. + /// - preprocessor: `DataPreprocessor` which filters incoming stream `Data` before serialization. + /// `PassthroughPreprocessor()` by default. + /// - Returns: The `DataStreamPublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishDecodable(type: T.Type = T.self, + queue: DispatchQueue = .main, + decoder: DataDecoder = JSONDecoder(), + preprocessor: DataPreprocessor = PassthroughPreprocessor()) -> DataStreamPublisher { + publishStream(using: DecodableStreamSerializer(decoder: decoder, + dataPreprocessor: preprocessor), + on: queue) + } +} + +/// A Combine `Publisher` that publishes the `DownloadResponse` of the provided `DownloadRequest`. +@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +public struct DownloadResponsePublisher: Publisher { + public typealias Output = DownloadResponse + public typealias Failure = Never + + private typealias Handler = (@escaping (_ response: DownloadResponse) -> Void) -> DownloadRequest + + private let request: DownloadRequest + private let responseHandler: Handler + + /// Creates an instance which will serialize responses using the provided `ResponseSerializer`. + /// + /// - Parameters: + /// - request: `DownloadRequest` for which to publish the response. + /// - queue: `DispatchQueue` on which the `DownloadResponse` value will be published. `.main` by default. + /// - serializer: `ResponseSerializer` used to produce the published `DownloadResponse`. + public init(_ request: DownloadRequest, queue: DispatchQueue, serializer: Serializer) + where Value == Serializer.SerializedObject { + self.request = request + responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) } + } + + /// Creates an instance which will serialize responses using the provided `DownloadResponseSerializerProtocol` value. + /// + /// - Parameters: + /// - request: `DownloadRequest` for which to publish the response. + /// - queue: `DispatchQueue` on which the `DataResponse` value will be published. `.main` by default. + /// - serializer: `DownloadResponseSerializerProtocol` used to produce the published `DownloadResponse`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public init(_ request: DownloadRequest, + queue: DispatchQueue, + serializer: Serializer) + where Value == Serializer.SerializedObject { + self.request = request + responseHandler = { request.response(queue: queue, responseSerializer: serializer, completionHandler: $0) } + } + + /// Publishes only the `Result` of the `DownloadResponse` value. + /// + /// - Returns: The `AnyPublisher` publishing the `Result` value. + public func result() -> AnyPublisher, Never> { + map(\.result).eraseToAnyPublisher() + } + + /// Publishes the `Result` of the `DownloadResponse` as a single `Value` or fail with the `AFError` instance. + /// + /// - Returns: The `AnyPublisher` publishing the stream. + public func value() -> AnyPublisher { + setFailureType(to: AFError.self).flatMap(\.result.publisher).eraseToAnyPublisher() + } + + public func receive(subscriber: S) where S: Subscriber, DownloadResponsePublisher.Failure == S.Failure, DownloadResponsePublisher.Output == S.Input { + subscriber.receive(subscription: Inner(request: request, + responseHandler: responseHandler, + downstream: subscriber)) + } + + private final class Inner: Subscription, Cancellable + where Downstream.Input == Output { + typealias Failure = Downstream.Failure + + @Protected + private var downstream: Downstream? + private let request: DownloadRequest + private let responseHandler: Handler + + init(request: DownloadRequest, responseHandler: @escaping Handler, downstream: Downstream) { + self.request = request + self.responseHandler = responseHandler + self.downstream = downstream + } + + func request(_ demand: Subscribers.Demand) { + assert(demand > 0) + + guard let downstream = downstream else { return } + + self.downstream = nil + responseHandler { response in + _ = downstream.receive(response) + downstream.receive(completion: .finished) + }.resume() + } + + func cancel() { + request.cancel() + downstream = nil + } + } +} + +extension DownloadRequest { + /// Creates a `DownloadResponsePublisher` for this instance using the given `ResponseSerializer` and `DispatchQueue`. + /// + /// - Parameters: + /// - serializer: `ResponseSerializer` used to serialize the response `Data` from disk. + /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published.`.main` by default. + /// + /// - Returns: The `DownloadResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishResponse(using serializer: Serializer, on queue: DispatchQueue = .main) -> DownloadResponsePublisher + where Serializer.SerializedObject == T { + DownloadResponsePublisher(self, queue: queue, serializer: serializer) + } + + /// Creates a `DownloadResponsePublisher` for this instance using the given `DownloadResponseSerializerProtocol` and + /// `DispatchQueue`. + /// + /// - Parameters: + /// - serializer: `DownloadResponseSerializer` used to serialize the response `Data` from disk. + /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published.`.main` by default. + /// + /// - Returns: The `DownloadResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishResponse(using serializer: Serializer, on queue: DispatchQueue = .main) -> DownloadResponsePublisher + where Serializer.SerializedObject == T { + DownloadResponsePublisher(self, queue: queue, serializer: serializer) + } + + /// Creates a `DownloadResponsePublisher` for this instance and uses a `URLResponseSerializer` to serialize the + /// response. + /// + /// - Parameter queue: `DispatchQueue` on which the `DownloadResponse` will be published. `.main` by default. + /// + /// - Returns: The `DownloadResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishURL(queue: DispatchQueue = .main) -> DownloadResponsePublisher { + publishResponse(using: URLResponseSerializer(), on: queue) + } + + /// Creates a `DownloadResponsePublisher` for this instance and uses a `DataResponseSerializer` to serialize the + /// response. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the `DownloadResponse` will be published. `.main` by default. + /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()` + /// by default. + /// - emptyResponseCodes: `Set` of HTTP status codes for which empty responses are allowed. `[204, 205]` by + /// default. + /// - emptyRequestMethods: `Set` of `HTTPMethod`s for which empty responses are allowed, regardless of + /// status code. `[.head]` by default. + /// + /// - Returns: The `DownloadResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishData(queue: DispatchQueue = .main, + preprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods) -> DownloadResponsePublisher { + publishResponse(using: DataResponseSerializer(dataPreprocessor: preprocessor, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + on: queue) + } + + /// Creates a `DownloadResponsePublisher` for this instance and uses a `StringResponseSerializer` to serialize the + /// response. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default. + /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. `PassthroughPreprocessor()` + /// by default. + /// - encoding: `String.Encoding` to parse the response. `nil` by default, in which case the encoding + /// will be determined by the server response, falling back to the default HTTP character + /// set, `ISO-8859-1`. + /// - emptyResponseCodes: `Set` of HTTP status codes for which empty responses are allowed. `[204, 205]` by + /// default. + /// - emptyRequestMethods: `Set` of `HTTPMethod`s for which empty responses are allowed, regardless of + /// status code. `[.head]` by default. + /// + /// - Returns: The `DownloadResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishString(queue: DispatchQueue = .main, + preprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor, + encoding: String.Encoding? = nil, + emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = StringResponseSerializer.defaultEmptyRequestMethods) -> DownloadResponsePublisher { + publishResponse(using: StringResponseSerializer(dataPreprocessor: preprocessor, + encoding: encoding, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + on: queue) + } + + @_disfavoredOverload + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + @available(*, deprecated, message: "Renamed publishDecodable(type:queue:preprocessor:decoder:emptyResponseCodes:emptyRequestMethods).") + public func publishDecodable(type: T.Type = T.self, + queue: DispatchQueue = .main, + preprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, + decoder: DataDecoder = JSONDecoder(), + emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, + emptyResponseMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods) -> DownloadResponsePublisher { + publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor, + decoder: decoder, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyResponseMethods), + on: queue) + } + + /// Creates a `DownloadResponsePublisher` for this instance and uses a `DecodableResponseSerializer` to serialize + /// the response. + /// + /// - Parameters: + /// - type: `Decodable` type to which to decode response `Data`. Inferred from the context by default. + /// - queue: `DispatchQueue` on which the `DataResponse` will be published. `.main` by default. + /// - preprocessor: `DataPreprocessor` which filters the `Data` before serialization. + /// `PassthroughPreprocessor()` by default. + /// - decoder: `DataDecoder` instance used to decode response `Data`. `JSONDecoder()` by default. + /// - emptyResponseCodes: `Set` of HTTP status codes for which empty responses are allowed. `[204, 205]` by + /// default. + /// - emptyRequestMethods: `Set` of `HTTPMethod`s for which empty responses are allowed, regardless + /// of status code. `[.head]` by default. + /// + /// - Returns: The `DownloadResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishDecodable(type: T.Type = T.self, + queue: DispatchQueue = .main, + preprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, + decoder: DataDecoder = JSONDecoder(), + emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods) -> DownloadResponsePublisher { + publishResponse(using: DecodableResponseSerializer(dataPreprocessor: preprocessor, + decoder: decoder, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + on: queue) + } +} + +@available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) +extension DownloadResponsePublisher where Value == URL? { + /// Creates an instance which publishes a `DownloadResponse` value without serialization. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public init(_ request: DownloadRequest, queue: DispatchQueue) { + self.request = request + responseHandler = { request.response(queue: queue, completionHandler: $0) } + } +} + +extension DownloadRequest { + /// Creates a `DownloadResponsePublisher` for this instance which does not serialize the response before publishing. + /// + /// - Parameter queue: `DispatchQueue` on which the `DownloadResponse` will be published. `.main` by default. + /// + /// - Returns: The `DownloadResponsePublisher`. + @available(macOS 10.15, iOS 13, watchOS 6, tvOS 13, *) + public func publishUnserialized(on queue: DispatchQueue = .main) -> DownloadResponsePublisher { + DownloadResponsePublisher(self, queue: queue) + } +} + +#endif diff --git a/Instagram-Clone/Pods/Alamofire/Source/Concurrency.swift b/Instagram-Clone/Pods/Alamofire/Source/Concurrency.swift new file mode 100644 index 0000000..2484335 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/Concurrency.swift @@ -0,0 +1,698 @@ +// +// Concurrency.swift +// +// Copyright (c) 2021 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 compiler(>=5.5.2) && canImport(_Concurrency) + +import Foundation + +// MARK: - Request Event Streams + +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +extension Request { + /// Creates a `StreamOf` for the instance's upload progress. + /// + /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// + /// - Returns: The `StreamOf`. + public func uploadProgress(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { + stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in + uploadProgress(queue: .singleEventQueue) { progress in + continuation.yield(progress) + } + } + } + + /// Creates a `StreamOf` for the instance's download progress. + /// + /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// + /// - Returns: The `StreamOf`. + public func downloadProgress(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { + stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in + downloadProgress(queue: .singleEventQueue) { progress in + continuation.yield(progress) + } + } + } + + /// Creates a `StreamOf` for the `URLRequest`s produced for the instance. + /// + /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// + /// - Returns: The `StreamOf`. + public func urlRequests(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { + stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in + onURLRequestCreation(on: .singleEventQueue) { request in + continuation.yield(request) + } + } + } + + /// Creates a `StreamOf` for the `URLSessionTask`s produced for the instance. + /// + /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// + /// - Returns: The `StreamOf`. + public func urlSessionTasks(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { + stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in + onURLSessionTaskCreation(on: .singleEventQueue) { task in + continuation.yield(task) + } + } + } + + /// Creates a `StreamOf` for the cURL descriptions produced for the instance. + /// + /// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// + /// - Returns: The `StreamOf`. + public func cURLDescriptions(bufferingPolicy: StreamOf.BufferingPolicy = .unbounded) -> StreamOf { + stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in + cURLDescription(on: .singleEventQueue) { description in + continuation.yield(description) + } + } + } + + private func stream(of type: T.Type = T.self, + bufferingPolicy: StreamOf.BufferingPolicy = .unbounded, + yielder: @escaping (StreamOf.Continuation) -> Void) -> StreamOf { + StreamOf(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in + yielder(continuation) + // Must come after serializers run in order to catch retry progress. + onFinish { + continuation.finish() + } + } + } +} + +// MARK: - DataTask + +/// Value used to `await` a `DataResponse` and associated values. +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +public struct DataTask { + /// `DataResponse` produced by the `DataRequest` and its response handler. + public var response: DataResponse { + get async { + if shouldAutomaticallyCancel { + return await withTaskCancellationHandler { + self.cancel() + } operation: { + await task.value + } + } else { + return await task.value + } + } + } + + /// `Result` of any response serialization performed for the `response`. + public var result: Result { + get async { await response.result } + } + + /// `Value` returned by the `response`. + public var value: Value { + get async throws { + try await result.get() + } + } + + private let request: DataRequest + private let task: Task, Never> + private let shouldAutomaticallyCancel: Bool + + fileprivate init(request: DataRequest, task: Task, Never>, shouldAutomaticallyCancel: Bool) { + self.request = request + self.task = task + self.shouldAutomaticallyCancel = shouldAutomaticallyCancel + } + + /// Cancel the underlying `DataRequest` and `Task`. + public func cancel() { + task.cancel() + } + + /// Resume the underlying `DataRequest`. + public func resume() { + request.resume() + } + + /// Suspend the underlying `DataRequest`. + public func suspend() { + request.suspend() + } +} + +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +extension DataRequest { + /// Creates a `DataTask` to `await` a `Data` value. + /// + /// - Parameters: + /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the + /// enclosing async context is cancelled. Only applies to `DataTask`'s async + /// properties. `false` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before completion. + /// - emptyResponseCodes: HTTP response codes for which empty responses are allowed. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// + /// - Returns: The `DataTask`. + public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods) -> DataTask { + serializingResponse(using: DataResponseSerializer(dataPreprocessor: dataPreprocessor, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + automaticallyCancelling: shouldAutomaticallyCancel) + } + + /// Creates a `DataTask` to `await` serialization of a `Decodable` value. + /// + /// - Parameters: + /// - type: `Decodable` type to decode from response data. + /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the + /// enclosing async context is cancelled. Only applies to `DataTask`'s async + /// properties. `false` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer. + /// `PassthroughPreprocessor()` by default. + /// - decoder: `DataDecoder` to use to decode the response. `JSONDecoder()` by default. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// + /// - Returns: The `DataTask`. + public func serializingDecodable(_ type: Value.Type = Value.self, + automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + dataPreprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, + decoder: DataDecoder = JSONDecoder(), + emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods) -> DataTask { + serializingResponse(using: DecodableResponseSerializer(dataPreprocessor: dataPreprocessor, + decoder: decoder, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + automaticallyCancelling: shouldAutomaticallyCancel) + } + + /// Creates a `DataTask` to `await` serialization of a `String` value. + /// + /// - Parameters: + /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the + /// enclosing async context is cancelled. Only applies to `DataTask`'s async + /// properties. `false` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer. + /// `PassthroughPreprocessor()` by default. + /// - encoding: `String.Encoding` to use during serialization. Defaults to `nil`, in which case + /// the encoding will be determined from the server response, falling back to the + /// default HTTP character set, `ISO-8859-1`. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// + /// - Returns: The `DataTask`. + public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor, + encoding: String.Encoding? = nil, + emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = StringResponseSerializer.defaultEmptyRequestMethods) -> DataTask { + serializingResponse(using: StringResponseSerializer(dataPreprocessor: dataPreprocessor, + encoding: encoding, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + automaticallyCancelling: shouldAutomaticallyCancel) + } + + /// Creates a `DataTask` to `await` serialization using the provided `ResponseSerializer` instance. + /// + /// - Parameters: + /// - serializer: `ResponseSerializer` responsible for serializing the request, response, and data. + /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the + /// enclosing async context is cancelled. Only applies to `DataTask`'s async + /// properties. `false` by default. + /// + /// - Returns: The `DataTask`. + public func serializingResponse(using serializer: Serializer, + automaticallyCancelling shouldAutomaticallyCancel: Bool = false) + -> DataTask { + dataTask(automaticallyCancelling: shouldAutomaticallyCancel) { + self.response(queue: .singleEventQueue, + responseSerializer: serializer, + completionHandler: $0) + } + } + + /// Creates a `DataTask` to `await` serialization using the provided `DataResponseSerializerProtocol` instance. + /// + /// - Parameters: + /// - serializer: `DataResponseSerializerProtocol` responsible for serializing the request, + /// response, and data. + /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the + /// enclosing async context is cancelled. Only applies to `DataTask`'s async + /// properties. `false` by default. + /// + /// - Returns: The `DataTask`. + public func serializingResponse(using serializer: Serializer, + automaticallyCancelling shouldAutomaticallyCancel: Bool = false) + -> DataTask { + dataTask(automaticallyCancelling: shouldAutomaticallyCancel) { + self.response(queue: .singleEventQueue, + responseSerializer: serializer, + completionHandler: $0) + } + } + + private func dataTask(automaticallyCancelling shouldAutomaticallyCancel: Bool, + forResponse onResponse: @escaping (@escaping (DataResponse) -> Void) -> Void) + -> DataTask { + let task = Task { + await withTaskCancellationHandler { + self.cancel() + } operation: { + await withCheckedContinuation { continuation in + onResponse { + continuation.resume(returning: $0) + } + } + } + } + + return DataTask(request: self, task: task, shouldAutomaticallyCancel: shouldAutomaticallyCancel) + } +} + +// MARK: - DownloadTask + +/// Value used to `await` a `DownloadResponse` and associated values. +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +public struct DownloadTask { + /// `DownloadResponse` produced by the `DownloadRequest` and its response handler. + public var response: DownloadResponse { + get async { + if shouldAutomaticallyCancel { + return await withTaskCancellationHandler { + self.cancel() + } operation: { + await task.value + } + } else { + return await task.value + } + } + } + + /// `Result` of any response serialization performed for the `response`. + public var result: Result { + get async { await response.result } + } + + /// `Value` returned by the `response`. + public var value: Value { + get async throws { + try await result.get() + } + } + + private let task: Task, Never> + private let request: DownloadRequest + private let shouldAutomaticallyCancel: Bool + + fileprivate init(request: DownloadRequest, task: Task, Never>, shouldAutomaticallyCancel: Bool) { + self.request = request + self.task = task + self.shouldAutomaticallyCancel = shouldAutomaticallyCancel + } + + /// Cancel the underlying `DownloadRequest` and `Task`. + public func cancel() { + task.cancel() + } + + /// Resume the underlying `DownloadRequest`. + public func resume() { + request.resume() + } + + /// Suspend the underlying `DownloadRequest`. + public func suspend() { + request.suspend() + } +} + +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +extension DownloadRequest { + /// Creates a `DownloadTask` to `await` a `Data` value. + /// + /// - Parameters: + /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the + /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async + /// properties. `false` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before completion. + /// - emptyResponseCodes: HTTP response codes for which empty responses are allowed. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// + /// - Returns: The `DownloadTask`. + public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods) -> DownloadTask { + serializingDownload(using: DataResponseSerializer(dataPreprocessor: dataPreprocessor, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + automaticallyCancelling: shouldAutomaticallyCancel) + } + + /// Creates a `DownloadTask` to `await` serialization of a `Decodable` value. + /// + /// - Note: This serializer reads the entire response into memory before parsing. + /// + /// - Parameters: + /// - type: `Decodable` type to decode from response data. + /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the + /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async + /// properties. `false` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer. + /// `PassthroughPreprocessor()` by default. + /// - decoder: `DataDecoder` to use to decode the response. `JSONDecoder()` by default. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// + /// - Returns: The `DownloadTask`. + public func serializingDecodable(_ type: Value.Type = Value.self, + automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + dataPreprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, + decoder: DataDecoder = JSONDecoder(), + emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods) -> DownloadTask { + serializingDownload(using: DecodableResponseSerializer(dataPreprocessor: dataPreprocessor, + decoder: decoder, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + automaticallyCancelling: shouldAutomaticallyCancel) + } + + /// Creates a `DownloadTask` to `await` serialization of the downloaded file's `URL` on disk. + /// + /// - Returns: The `DownloadTask`. + public func serializingDownloadedFileURL() -> DownloadTask { + serializingDownload(using: URLResponseSerializer()) + } + + /// Creates a `DownloadTask` to `await` serialization of a `String` value. + /// + /// - Parameters: + /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the + /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async + /// properties. `false` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the + /// serializer. `PassthroughPreprocessor()` by default. + /// - encoding: `String.Encoding` to use during serialization. Defaults to `nil`, in which case + /// the encoding will be determined from the server response, falling back to the + /// default HTTP character set, `ISO-8859-1`. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// + /// - Returns: The `DownloadTask`. + public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = false, + dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor, + encoding: String.Encoding? = nil, + emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = StringResponseSerializer.defaultEmptyRequestMethods) -> DownloadTask { + serializingDownload(using: StringResponseSerializer(dataPreprocessor: dataPreprocessor, + encoding: encoding, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + automaticallyCancelling: shouldAutomaticallyCancel) + } + + /// Creates a `DownloadTask` to `await` serialization using the provided `ResponseSerializer` instance. + /// + /// - Parameters: + /// - serializer: `ResponseSerializer` responsible for serializing the request, response, and data. + /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the + /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async + /// properties. `false` by default. + /// + /// - Returns: The `DownloadTask`. + public func serializingDownload(using serializer: Serializer, + automaticallyCancelling shouldAutomaticallyCancel: Bool = false) + -> DownloadTask { + downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) { + self.response(queue: .singleEventQueue, + responseSerializer: serializer, + completionHandler: $0) + } + } + + /// Creates a `DownloadTask` to `await` serialization using the provided `DownloadResponseSerializerProtocol` + /// instance. + /// + /// - Parameters: + /// - serializer: `DownloadResponseSerializerProtocol` responsible for serializing the request, + /// response, and data. + /// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the + /// enclosing async context is cancelled. Only applies to `DownloadTask`'s async + /// properties. `false` by default. + /// + /// - Returns: The `DownloadTask`. + public func serializingDownload(using serializer: Serializer, + automaticallyCancelling shouldAutomaticallyCancel: Bool = false) + -> DownloadTask { + downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) { + self.response(queue: .singleEventQueue, + responseSerializer: serializer, + completionHandler: $0) + } + } + + private func downloadTask(automaticallyCancelling shouldAutomaticallyCancel: Bool, + forResponse onResponse: @escaping (@escaping (DownloadResponse) -> Void) -> Void) + -> DownloadTask { + let task = Task { + await withTaskCancellationHandler { + self.cancel() + } operation: { + await withCheckedContinuation { continuation in + onResponse { + continuation.resume(returning: $0) + } + } + } + } + + return DownloadTask(request: self, task: task, shouldAutomaticallyCancel: shouldAutomaticallyCancel) + } +} + +// MARK: - DataStreamTask + +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +public struct DataStreamTask { + // Type of created streams. + public typealias Stream = StreamOf> + + private let request: DataStreamRequest + + fileprivate init(request: DataStreamRequest) { + self.request = request + } + + /// Creates a `Stream` of `Data` values from the underlying `DataStreamRequest`. + /// + /// - Parameters: + /// - shouldAutomaticallyCancel: `Bool` indicating whether the underlying `DataStreamRequest` should be canceled + /// which observation of the stream stops. `true` by default. + /// - bufferingPolicy: ` BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// + /// - Returns: The `Stream`. + public func streamingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = true, bufferingPolicy: Stream.BufferingPolicy = .unbounded) -> Stream { + createStream(automaticallyCancelling: shouldAutomaticallyCancel, bufferingPolicy: bufferingPolicy) { onStream in + self.request.responseStream(on: .streamCompletionQueue(forRequestID: request.id), stream: onStream) + } + } + + /// Creates a `Stream` of `UTF-8` `String`s from the underlying `DataStreamRequest`. + /// + /// - Parameters: + /// - shouldAutomaticallyCancel: `Bool` indicating whether the underlying `DataStreamRequest` should be canceled + /// which observation of the stream stops. `true` by default. + /// - bufferingPolicy: ` BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// - Returns: + public func streamingStrings(automaticallyCancelling shouldAutomaticallyCancel: Bool = true, bufferingPolicy: Stream.BufferingPolicy = .unbounded) -> Stream { + createStream(automaticallyCancelling: shouldAutomaticallyCancel, bufferingPolicy: bufferingPolicy) { onStream in + self.request.responseStreamString(on: .streamCompletionQueue(forRequestID: request.id), stream: onStream) + } + } + + /// Creates a `Stream` of `Decodable` values from the underlying `DataStreamRequest`. + /// + /// - Parameters: + /// - type: `Decodable` type to be serialized from stream payloads. + /// - shouldAutomaticallyCancel: `Bool` indicating whether the underlying `DataStreamRequest` should be canceled + /// which observation of the stream stops. `true` by default. + /// - bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// + /// - Returns: The `Stream`. + public func streamingDecodables(_ type: T.Type = T.self, + automaticallyCancelling shouldAutomaticallyCancel: Bool = true, + bufferingPolicy: Stream.BufferingPolicy = .unbounded) + -> Stream where T: Decodable { + streamingResponses(serializedUsing: DecodableStreamSerializer(), + automaticallyCancelling: shouldAutomaticallyCancel, + bufferingPolicy: bufferingPolicy) + } + + /// Creates a `Stream` of values using the provided `DataStreamSerializer` from the underlying `DataStreamRequest`. + /// + /// - Parameters: + /// - serializer: `DataStreamSerializer` to use to serialize incoming `Data`. + /// - shouldAutomaticallyCancel: `Bool` indicating whether the underlying `DataStreamRequest` should be canceled + /// which observation of the stream stops. `true` by default. + /// - bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default. + /// + /// - Returns: The `Stream`. + public func streamingResponses(serializedUsing serializer: Serializer, + automaticallyCancelling shouldAutomaticallyCancel: Bool = true, + bufferingPolicy: Stream.BufferingPolicy = .unbounded) + -> Stream { + createStream(automaticallyCancelling: shouldAutomaticallyCancel, bufferingPolicy: bufferingPolicy) { onStream in + self.request.responseStream(using: serializer, + on: .streamCompletionQueue(forRequestID: request.id), + stream: onStream) + } + } + + private func createStream(automaticallyCancelling shouldAutomaticallyCancel: Bool = true, + bufferingPolicy: Stream.BufferingPolicy = .unbounded, + forResponse onResponse: @escaping (@escaping (DataStreamRequest.Stream) -> Void) -> Void) + -> Stream { + StreamOf(bufferingPolicy: bufferingPolicy) { + guard shouldAutomaticallyCancel, + request.isInitialized || request.isResumed || request.isSuspended else { return } + + cancel() + } builder: { continuation in + onResponse { stream in + continuation.yield(stream) + if case .complete = stream.event { + continuation.finish() + } + } + } + } + + /// Cancel the underlying `DataStreamRequest`. + public func cancel() { + request.cancel() + } + + /// Resume the underlying `DataStreamRequest`. + public func resume() { + request.resume() + } + + /// Suspend the underlying `DataStreamRequest`. + public func suspend() { + request.suspend() + } +} + +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +extension DataStreamRequest { + /// Creates a `DataStreamTask` used to `await` streams of serialized values. + /// + /// - Returns: The `DataStreamTask`. + public func streamTask() -> DataStreamTask { + DataStreamTask(request: self) + } +} + +extension DispatchQueue { + fileprivate static let singleEventQueue = DispatchQueue(label: "org.alamofire.concurrencySingleEventQueue", + attributes: .concurrent) + + fileprivate static func streamCompletionQueue(forRequestID id: UUID) -> DispatchQueue { + DispatchQueue(label: "org.alamofire.concurrencyStreamCompletionQueue-\(id)", target: .singleEventQueue) + } +} + +/// An asynchronous sequence generated from an underlying `AsyncStream`. Only produced by Alamofire. +@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *) +public struct StreamOf: AsyncSequence { + public typealias AsyncIterator = Iterator + public typealias BufferingPolicy = AsyncStream.Continuation.BufferingPolicy + fileprivate typealias Continuation = AsyncStream.Continuation + + private let bufferingPolicy: BufferingPolicy + private let onTermination: (() -> Void)? + private let builder: (Continuation) -> Void + + fileprivate init(bufferingPolicy: BufferingPolicy = .unbounded, + onTermination: (() -> Void)? = nil, + builder: @escaping (Continuation) -> Void) { + self.bufferingPolicy = bufferingPolicy + self.onTermination = onTermination + self.builder = builder + } + + public func makeAsyncIterator() -> Iterator { + var continuation: AsyncStream.Continuation? + let stream = AsyncStream { innerContinuation in + continuation = innerContinuation + builder(innerContinuation) + } + + return Iterator(iterator: stream.makeAsyncIterator()) { + continuation?.finish() + self.onTermination?() + } + } + + public struct Iterator: AsyncIteratorProtocol { + private final class Token { + private let onDeinit: () -> Void + + init(onDeinit: @escaping () -> Void) { + self.onDeinit = onDeinit + } + + deinit { + onDeinit() + } + } + + private var iterator: AsyncStream.AsyncIterator + private let token: Token + + init(iterator: AsyncStream.AsyncIterator, onCancellation: @escaping () -> Void) { + self.iterator = iterator + token = Token(onDeinit: onCancellation) + } + + public mutating func next() async -> Element? { + await iterator.next() + } + } +} + +#endif diff --git a/Instagram-Clone/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift b/Instagram-Clone/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift new file mode 100644 index 0000000..10cd273 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift @@ -0,0 +1,37 @@ +// +// DispatchQueue+Alamofire.swift +// +// Copyright (c) 2014-2018 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 { + /// Execute the provided closure after a `TimeInterval`. + /// + /// - Parameters: + /// - delay: `TimeInterval` to delay execution. + /// - closure: Closure to execute. + func after(_ delay: TimeInterval, execute closure: @escaping () -> Void) { + asyncAfter(deadline: .now() + delay, execute: closure) + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/EventMonitor.swift b/Instagram-Clone/Pods/Alamofire/Source/EventMonitor.swift new file mode 100644 index 0000000..3b09671 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/EventMonitor.swift @@ -0,0 +1,892 @@ +// +// EventMonitor.swift +// +// Copyright (c) 2014-2018 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 + +/// Protocol outlining the lifetime events inside Alamofire. It includes both events received from the various +/// `URLSession` delegate protocols as well as various events from the lifetime of `Request` and its subclasses. +public protocol EventMonitor { + /// The `DispatchQueue` onto which Alamofire's root `CompositeEventMonitor` will dispatch events. `.main` by default. + var queue: DispatchQueue { get } + + // MARK: - URLSession Events + + // MARK: URLSessionDelegate Events + + /// Event called during `URLSessionDelegate`'s `urlSession(_:didBecomeInvalidWithError:)` method. + func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) + + // MARK: URLSessionTaskDelegate Events + + /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:didReceive:completionHandler:)` method. + func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge) + + /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)` method. + func urlSession(_ session: URLSession, + task: URLSessionTask, + didSendBodyData bytesSent: Int64, + totalBytesSent: Int64, + totalBytesExpectedToSend: Int64) + + /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:needNewBodyStream:)` method. + func urlSession(_ session: URLSession, taskNeedsNewBodyStream task: URLSessionTask) + + /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)` method. + func urlSession(_ session: URLSession, + task: URLSessionTask, + willPerformHTTPRedirection response: HTTPURLResponse, + newRequest request: URLRequest) + + /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:didFinishCollecting:)` method. + func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) + + /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:didCompleteWithError:)` method. + func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) + + /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:taskIsWaitingForConnectivity:)` method. + @available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) + func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) + + // MARK: URLSessionDataDelegate Events + + /// Event called during `URLSessionDataDelegate`'s `urlSession(_:dataTask:didReceive:)` method. + func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) + + /// Event called during `URLSessionDataDelegate`'s `urlSession(_:dataTask:willCacheResponse:completionHandler:)` method. + func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, willCacheResponse proposedResponse: CachedURLResponse) + + // MARK: URLSessionDownloadDelegate Events + + /// Event called during `URLSessionDownloadDelegate`'s `urlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:)` method. + func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didResumeAtOffset fileOffset: Int64, + expectedTotalBytes: Int64) + + /// Event called during `URLSessionDownloadDelegate`'s `urlSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)` method. + func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didWriteData bytesWritten: Int64, + totalBytesWritten: Int64, + totalBytesExpectedToWrite: Int64) + + /// Event called during `URLSessionDownloadDelegate`'s `urlSession(_:downloadTask:didFinishDownloadingTo:)` method. + func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) + + // MARK: - Request Events + + /// Event called when a `URLRequest` is first created for a `Request`. If a `RequestAdapter` is active, the + /// `URLRequest` will be adapted before being issued. + func request(_ request: Request, didCreateInitialURLRequest urlRequest: URLRequest) + + /// Event called when the attempt to create a `URLRequest` from a `Request`'s original `URLRequestConvertible` value fails. + func request(_ request: Request, didFailToCreateURLRequestWithError error: AFError) + + /// Event called when a `RequestAdapter` adapts the `Request`'s initial `URLRequest`. + func request(_ request: Request, didAdaptInitialRequest initialRequest: URLRequest, to adaptedRequest: URLRequest) + + /// Event called when a `RequestAdapter` fails to adapt the `Request`'s initial `URLRequest`. + func request(_ request: Request, didFailToAdaptURLRequest initialRequest: URLRequest, withError error: AFError) + + /// Event called when a final `URLRequest` is created for a `Request`. + func request(_ request: Request, didCreateURLRequest urlRequest: URLRequest) + + /// Event called when a `URLSessionTask` subclass instance is created for a `Request`. + func request(_ request: Request, didCreateTask task: URLSessionTask) + + /// Event called when a `Request` receives a `URLSessionTaskMetrics` value. + func request(_ request: Request, didGatherMetrics metrics: URLSessionTaskMetrics) + + /// Event called when a `Request` fails due to an error created by Alamofire. e.g. When certificate pinning fails. + func request(_ request: Request, didFailTask task: URLSessionTask, earlyWithError error: AFError) + + /// Event called when a `Request`'s task completes, possibly with an error. A `Request` may receive this event + /// multiple times if it is retried. + func request(_ request: Request, didCompleteTask task: URLSessionTask, with error: AFError?) + + /// Event called when a `Request` is about to be retried. + func requestIsRetrying(_ request: Request) + + /// Event called when a `Request` finishes and response serializers are being called. + func requestDidFinish(_ request: Request) + + /// Event called when a `Request` receives a `resume` call. + func requestDidResume(_ request: Request) + + /// Event called when a `Request`'s associated `URLSessionTask` is resumed. + func request(_ request: Request, didResumeTask task: URLSessionTask) + + /// Event called when a `Request` receives a `suspend` call. + func requestDidSuspend(_ request: Request) + + /// Event called when a `Request`'s associated `URLSessionTask` is suspended. + func request(_ request: Request, didSuspendTask task: URLSessionTask) + + /// Event called when a `Request` receives a `cancel` call. + func requestDidCancel(_ request: Request) + + /// Event called when a `Request`'s associated `URLSessionTask` is cancelled. + func request(_ request: Request, didCancelTask task: URLSessionTask) + + // MARK: DataRequest Events + + /// Event called when a `DataRequest` calls a `Validation`. + func request(_ request: DataRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + data: Data?, + withResult result: Request.ValidationResult) + + /// Event called when a `DataRequest` creates a `DataResponse` value without calling a `ResponseSerializer`. + func request(_ request: DataRequest, didParseResponse response: DataResponse) + + /// Event called when a `DataRequest` calls a `ResponseSerializer` and creates a generic `DataResponse`. + func request(_ request: DataRequest, didParseResponse response: DataResponse) + + // MARK: DataStreamRequest Events + + /// Event called when a `DataStreamRequest` calls a `Validation` closure. + /// + /// - Parameters: + /// - request: `DataStreamRequest` which is calling the `Validation`. + /// - urlRequest: `URLRequest` of the request being validated. + /// - response: `HTTPURLResponse` of the request being validated. + /// - result: Produced `ValidationResult`. + func request(_ request: DataStreamRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + withResult result: Request.ValidationResult) + + /// Event called when a `DataStreamSerializer` produces a value from streamed `Data`. + /// + /// - Parameters: + /// - request: `DataStreamRequest` for which the value was serialized. + /// - result: `Result` of the serialization attempt. + func request(_ request: DataStreamRequest, didParseStream result: Result) + + // MARK: UploadRequest Events + + /// Event called when an `UploadRequest` creates its `Uploadable` value, indicating the type of upload it represents. + func request(_ request: UploadRequest, didCreateUploadable uploadable: UploadRequest.Uploadable) + + /// Event called when an `UploadRequest` failed to create its `Uploadable` value due to an error. + func request(_ request: UploadRequest, didFailToCreateUploadableWithError error: AFError) + + /// Event called when an `UploadRequest` provides the `InputStream` from its `Uploadable` value. This only occurs if + /// the `InputStream` does not wrap a `Data` value or file `URL`. + func request(_ request: UploadRequest, didProvideInputStream stream: InputStream) + + // MARK: DownloadRequest Events + + /// Event called when a `DownloadRequest`'s `URLSessionDownloadTask` finishes and the temporary file has been moved. + func request(_ request: DownloadRequest, didFinishDownloadingUsing task: URLSessionTask, with result: Result) + + /// Event called when a `DownloadRequest`'s `Destination` closure is called and creates the destination URL the + /// downloaded file will be moved to. + func request(_ request: DownloadRequest, didCreateDestinationURL url: URL) + + /// Event called when a `DownloadRequest` calls a `Validation`. + func request(_ request: DownloadRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + fileURL: URL?, + withResult result: Request.ValidationResult) + + /// Event called when a `DownloadRequest` creates a `DownloadResponse` without calling a `ResponseSerializer`. + func request(_ request: DownloadRequest, didParseResponse response: DownloadResponse) + + /// Event called when a `DownloadRequest` calls a `DownloadResponseSerializer` and creates a generic `DownloadResponse` + func request(_ request: DownloadRequest, didParseResponse response: DownloadResponse) +} + +extension EventMonitor { + /// The default queue on which `CompositeEventMonitor`s will call the `EventMonitor` methods. `.main` by default. + public var queue: DispatchQueue { .main } + + // MARK: Default Implementations + + public func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {} + public func urlSession(_ session: URLSession, + task: URLSessionTask, + didReceive challenge: URLAuthenticationChallenge) {} + public func urlSession(_ session: URLSession, + task: URLSessionTask, + didSendBodyData bytesSent: Int64, + totalBytesSent: Int64, + totalBytesExpectedToSend: Int64) {} + public func urlSession(_ session: URLSession, taskNeedsNewBodyStream task: URLSessionTask) {} + public func urlSession(_ session: URLSession, + task: URLSessionTask, + willPerformHTTPRedirection response: HTTPURLResponse, + newRequest request: URLRequest) {} + public func urlSession(_ session: URLSession, + task: URLSessionTask, + didFinishCollecting metrics: URLSessionTaskMetrics) {} + public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {} + public func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) {} + public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {} + public func urlSession(_ session: URLSession, + dataTask: URLSessionDataTask, + willCacheResponse proposedResponse: CachedURLResponse) {} + public func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didResumeAtOffset fileOffset: Int64, + expectedTotalBytes: Int64) {} + public func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didWriteData bytesWritten: Int64, + totalBytesWritten: Int64, + totalBytesExpectedToWrite: Int64) {} + public func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didFinishDownloadingTo location: URL) {} + public func request(_ request: Request, didCreateInitialURLRequest urlRequest: URLRequest) {} + public func request(_ request: Request, didFailToCreateURLRequestWithError error: AFError) {} + public func request(_ request: Request, + didAdaptInitialRequest initialRequest: URLRequest, + to adaptedRequest: URLRequest) {} + public func request(_ request: Request, + didFailToAdaptURLRequest initialRequest: URLRequest, + withError error: AFError) {} + public func request(_ request: Request, didCreateURLRequest urlRequest: URLRequest) {} + public func request(_ request: Request, didCreateTask task: URLSessionTask) {} + public func request(_ request: Request, didGatherMetrics metrics: URLSessionTaskMetrics) {} + public func request(_ request: Request, didFailTask task: URLSessionTask, earlyWithError error: AFError) {} + public func request(_ request: Request, didCompleteTask task: URLSessionTask, with error: AFError?) {} + public func requestIsRetrying(_ request: Request) {} + public func requestDidFinish(_ request: Request) {} + public func requestDidResume(_ request: Request) {} + public func request(_ request: Request, didResumeTask task: URLSessionTask) {} + public func requestDidSuspend(_ request: Request) {} + public func request(_ request: Request, didSuspendTask task: URLSessionTask) {} + public func requestDidCancel(_ request: Request) {} + public func request(_ request: Request, didCancelTask task: URLSessionTask) {} + public func request(_ request: DataRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + data: Data?, + withResult result: Request.ValidationResult) {} + public func request(_ request: DataRequest, didParseResponse response: DataResponse) {} + public func request(_ request: DataRequest, didParseResponse response: DataResponse) {} + public func request(_ request: DataStreamRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + withResult result: Request.ValidationResult) {} + public func request(_ request: DataStreamRequest, didParseStream result: Result) {} + public func request(_ request: UploadRequest, didCreateUploadable uploadable: UploadRequest.Uploadable) {} + public func request(_ request: UploadRequest, didFailToCreateUploadableWithError error: AFError) {} + public func request(_ request: UploadRequest, didProvideInputStream stream: InputStream) {} + public func request(_ request: DownloadRequest, didFinishDownloadingUsing task: URLSessionTask, with result: Result) {} + public func request(_ request: DownloadRequest, didCreateDestinationURL url: URL) {} + public func request(_ request: DownloadRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + fileURL: URL?, + withResult result: Request.ValidationResult) {} + public func request(_ request: DownloadRequest, didParseResponse response: DownloadResponse) {} + public func request(_ request: DownloadRequest, didParseResponse response: DownloadResponse) {} +} + +/// An `EventMonitor` which can contain multiple `EventMonitor`s and calls their methods on their queues. +public final class CompositeEventMonitor: EventMonitor { + public let queue = DispatchQueue(label: "org.alamofire.compositeEventMonitor", qos: .utility) + + let monitors: [EventMonitor] + + init(monitors: [EventMonitor]) { + self.monitors = monitors + } + + func performEvent(_ event: @escaping (EventMonitor) -> Void) { + queue.async { + for monitor in self.monitors { + monitor.queue.async { event(monitor) } + } + } + } + + public func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) { + performEvent { $0.urlSession(session, didBecomeInvalidWithError: error) } + } + + public func urlSession(_ session: URLSession, + task: URLSessionTask, + didReceive challenge: URLAuthenticationChallenge) { + performEvent { $0.urlSession(session, task: task, didReceive: challenge) } + } + + public func urlSession(_ session: URLSession, + task: URLSessionTask, + didSendBodyData bytesSent: Int64, + totalBytesSent: Int64, + totalBytesExpectedToSend: Int64) { + performEvent { + $0.urlSession(session, + task: task, + didSendBodyData: bytesSent, + totalBytesSent: totalBytesSent, + totalBytesExpectedToSend: totalBytesExpectedToSend) + } + } + + public func urlSession(_ session: URLSession, taskNeedsNewBodyStream task: URLSessionTask) { + performEvent { + $0.urlSession(session, taskNeedsNewBodyStream: task) + } + } + + public func urlSession(_ session: URLSession, + task: URLSessionTask, + willPerformHTTPRedirection response: HTTPURLResponse, + newRequest request: URLRequest) { + performEvent { + $0.urlSession(session, + task: task, + willPerformHTTPRedirection: response, + newRequest: request) + } + } + + public func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) { + performEvent { $0.urlSession(session, task: task, didFinishCollecting: metrics) } + } + + public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { + performEvent { $0.urlSession(session, task: task, didCompleteWithError: error) } + } + + @available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) + public func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) { + performEvent { $0.urlSession(session, taskIsWaitingForConnectivity: task) } + } + + public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { + performEvent { $0.urlSession(session, dataTask: dataTask, didReceive: data) } + } + + public func urlSession(_ session: URLSession, + dataTask: URLSessionDataTask, + willCacheResponse proposedResponse: CachedURLResponse) { + performEvent { $0.urlSession(session, dataTask: dataTask, willCacheResponse: proposedResponse) } + } + + public func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didResumeAtOffset fileOffset: Int64, + expectedTotalBytes: Int64) { + performEvent { + $0.urlSession(session, + downloadTask: downloadTask, + didResumeAtOffset: fileOffset, + expectedTotalBytes: expectedTotalBytes) + } + } + + public func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didWriteData bytesWritten: Int64, + totalBytesWritten: Int64, + totalBytesExpectedToWrite: Int64) { + performEvent { + $0.urlSession(session, + downloadTask: downloadTask, + didWriteData: bytesWritten, + totalBytesWritten: totalBytesWritten, + totalBytesExpectedToWrite: totalBytesExpectedToWrite) + } + } + + public func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didFinishDownloadingTo location: URL) { + performEvent { $0.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location) } + } + + public func request(_ request: Request, didCreateInitialURLRequest urlRequest: URLRequest) { + performEvent { $0.request(request, didCreateInitialURLRequest: urlRequest) } + } + + public func request(_ request: Request, didFailToCreateURLRequestWithError error: AFError) { + performEvent { $0.request(request, didFailToCreateURLRequestWithError: error) } + } + + public func request(_ request: Request, didAdaptInitialRequest initialRequest: URLRequest, to adaptedRequest: URLRequest) { + performEvent { $0.request(request, didAdaptInitialRequest: initialRequest, to: adaptedRequest) } + } + + public func request(_ request: Request, didFailToAdaptURLRequest initialRequest: URLRequest, withError error: AFError) { + performEvent { $0.request(request, didFailToAdaptURLRequest: initialRequest, withError: error) } + } + + public func request(_ request: Request, didCreateURLRequest urlRequest: URLRequest) { + performEvent { $0.request(request, didCreateURLRequest: urlRequest) } + } + + public func request(_ request: Request, didCreateTask task: URLSessionTask) { + performEvent { $0.request(request, didCreateTask: task) } + } + + public func request(_ request: Request, didGatherMetrics metrics: URLSessionTaskMetrics) { + performEvent { $0.request(request, didGatherMetrics: metrics) } + } + + public func request(_ request: Request, didFailTask task: URLSessionTask, earlyWithError error: AFError) { + performEvent { $0.request(request, didFailTask: task, earlyWithError: error) } + } + + public func request(_ request: Request, didCompleteTask task: URLSessionTask, with error: AFError?) { + performEvent { $0.request(request, didCompleteTask: task, with: error) } + } + + public func requestIsRetrying(_ request: Request) { + performEvent { $0.requestIsRetrying(request) } + } + + public func requestDidFinish(_ request: Request) { + performEvent { $0.requestDidFinish(request) } + } + + public func requestDidResume(_ request: Request) { + performEvent { $0.requestDidResume(request) } + } + + public func request(_ request: Request, didResumeTask task: URLSessionTask) { + performEvent { $0.request(request, didResumeTask: task) } + } + + public func requestDidSuspend(_ request: Request) { + performEvent { $0.requestDidSuspend(request) } + } + + public func request(_ request: Request, didSuspendTask task: URLSessionTask) { + performEvent { $0.request(request, didSuspendTask: task) } + } + + public func requestDidCancel(_ request: Request) { + performEvent { $0.requestDidCancel(request) } + } + + public func request(_ request: Request, didCancelTask task: URLSessionTask) { + performEvent { $0.request(request, didCancelTask: task) } + } + + public func request(_ request: DataRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + data: Data?, + withResult result: Request.ValidationResult) { + performEvent { $0.request(request, + didValidateRequest: urlRequest, + response: response, + data: data, + withResult: result) + } + } + + public func request(_ request: DataRequest, didParseResponse response: DataResponse) { + performEvent { $0.request(request, didParseResponse: response) } + } + + public func request(_ request: DataRequest, didParseResponse response: DataResponse) { + performEvent { $0.request(request, didParseResponse: response) } + } + + public func request(_ request: DataStreamRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + withResult result: Request.ValidationResult) { + performEvent { $0.request(request, + didValidateRequest: urlRequest, + response: response, + withResult: result) + } + } + + public func request(_ request: DataStreamRequest, didParseStream result: Result) { + performEvent { $0.request(request, didParseStream: result) } + } + + public func request(_ request: UploadRequest, didCreateUploadable uploadable: UploadRequest.Uploadable) { + performEvent { $0.request(request, didCreateUploadable: uploadable) } + } + + public func request(_ request: UploadRequest, didFailToCreateUploadableWithError error: AFError) { + performEvent { $0.request(request, didFailToCreateUploadableWithError: error) } + } + + public func request(_ request: UploadRequest, didProvideInputStream stream: InputStream) { + performEvent { $0.request(request, didProvideInputStream: stream) } + } + + public func request(_ request: DownloadRequest, didFinishDownloadingUsing task: URLSessionTask, with result: Result) { + performEvent { $0.request(request, didFinishDownloadingUsing: task, with: result) } + } + + public func request(_ request: DownloadRequest, didCreateDestinationURL url: URL) { + performEvent { $0.request(request, didCreateDestinationURL: url) } + } + + public func request(_ request: DownloadRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + fileURL: URL?, + withResult result: Request.ValidationResult) { + performEvent { $0.request(request, + didValidateRequest: urlRequest, + response: response, + fileURL: fileURL, + withResult: result) } + } + + public func request(_ request: DownloadRequest, didParseResponse response: DownloadResponse) { + performEvent { $0.request(request, didParseResponse: response) } + } + + public func request(_ request: DownloadRequest, didParseResponse response: DownloadResponse) { + performEvent { $0.request(request, didParseResponse: response) } + } +} + +/// `EventMonitor` that allows optional closures to be set to receive events. +open class ClosureEventMonitor: EventMonitor { + /// Closure called on the `urlSession(_:didBecomeInvalidWithError:)` event. + open var sessionDidBecomeInvalidWithError: ((URLSession, Error?) -> Void)? + + /// Closure called on the `urlSession(_:task:didReceive:completionHandler:)`. + open var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> Void)? + + /// Closure that receives `urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)` event. + open var taskDidSendBodyData: ((URLSession, URLSessionTask, Int64, Int64, Int64) -> Void)? + + /// Closure called on the `urlSession(_:task:needNewBodyStream:)` event. + open var taskNeedNewBodyStream: ((URLSession, URLSessionTask) -> Void)? + + /// Closure called on the `urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)` event. + open var taskWillPerformHTTPRedirection: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest) -> Void)? + + /// Closure called on the `urlSession(_:task:didFinishCollecting:)` event. + open var taskDidFinishCollectingMetrics: ((URLSession, URLSessionTask, URLSessionTaskMetrics) -> Void)? + + /// Closure called on the `urlSession(_:task:didCompleteWithError:)` event. + open var taskDidComplete: ((URLSession, URLSessionTask, Error?) -> Void)? + + /// Closure called on the `urlSession(_:taskIsWaitingForConnectivity:)` event. + open var taskIsWaitingForConnectivity: ((URLSession, URLSessionTask) -> Void)? + + /// Closure that receives the `urlSession(_:dataTask:didReceive:)` event. + open var dataTaskDidReceiveData: ((URLSession, URLSessionDataTask, Data) -> Void)? + + /// Closure called on the `urlSession(_:dataTask:willCacheResponse:completionHandler:)` event. + open var dataTaskWillCacheResponse: ((URLSession, URLSessionDataTask, CachedURLResponse) -> Void)? + + /// Closure called on the `urlSession(_:downloadTask:didFinishDownloadingTo:)` event. + open var downloadTaskDidFinishDownloadingToURL: ((URLSession, URLSessionDownloadTask, URL) -> Void)? + + /// Closure called on the `urlSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)` + /// event. + open var downloadTaskDidWriteData: ((URLSession, URLSessionDownloadTask, Int64, Int64, Int64) -> Void)? + + /// Closure called on the `urlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:)` event. + open var downloadTaskDidResumeAtOffset: ((URLSession, URLSessionDownloadTask, Int64, Int64) -> Void)? + + // MARK: - Request Events + + /// Closure called on the `request(_:didCreateInitialURLRequest:)` event. + open var requestDidCreateInitialURLRequest: ((Request, URLRequest) -> Void)? + + /// Closure called on the `request(_:didFailToCreateURLRequestWithError:)` event. + open var requestDidFailToCreateURLRequestWithError: ((Request, AFError) -> Void)? + + /// Closure called on the `request(_:didAdaptInitialRequest:to:)` event. + open var requestDidAdaptInitialRequestToAdaptedRequest: ((Request, URLRequest, URLRequest) -> Void)? + + /// Closure called on the `request(_:didFailToAdaptURLRequest:withError:)` event. + open var requestDidFailToAdaptURLRequestWithError: ((Request, URLRequest, AFError) -> Void)? + + /// Closure called on the `request(_:didCreateURLRequest:)` event. + open var requestDidCreateURLRequest: ((Request, URLRequest) -> Void)? + + /// Closure called on the `request(_:didCreateTask:)` event. + open var requestDidCreateTask: ((Request, URLSessionTask) -> Void)? + + /// Closure called on the `request(_:didGatherMetrics:)` event. + open var requestDidGatherMetrics: ((Request, URLSessionTaskMetrics) -> Void)? + + /// Closure called on the `request(_:didFailTask:earlyWithError:)` event. + open var requestDidFailTaskEarlyWithError: ((Request, URLSessionTask, AFError) -> Void)? + + /// Closure called on the `request(_:didCompleteTask:with:)` event. + open var requestDidCompleteTaskWithError: ((Request, URLSessionTask, AFError?) -> Void)? + + /// Closure called on the `requestIsRetrying(_:)` event. + open var requestIsRetrying: ((Request) -> Void)? + + /// Closure called on the `requestDidFinish(_:)` event. + open var requestDidFinish: ((Request) -> Void)? + + /// Closure called on the `requestDidResume(_:)` event. + open var requestDidResume: ((Request) -> Void)? + + /// Closure called on the `request(_:didResumeTask:)` event. + open var requestDidResumeTask: ((Request, URLSessionTask) -> Void)? + + /// Closure called on the `requestDidSuspend(_:)` event. + open var requestDidSuspend: ((Request) -> Void)? + + /// Closure called on the `request(_:didSuspendTask:)` event. + open var requestDidSuspendTask: ((Request, URLSessionTask) -> Void)? + + /// Closure called on the `requestDidCancel(_:)` event. + open var requestDidCancel: ((Request) -> Void)? + + /// Closure called on the `request(_:didCancelTask:)` event. + open var requestDidCancelTask: ((Request, URLSessionTask) -> Void)? + + /// Closure called on the `request(_:didValidateRequest:response:data:withResult:)` event. + open var requestDidValidateRequestResponseDataWithResult: ((DataRequest, URLRequest?, HTTPURLResponse, Data?, Request.ValidationResult) -> Void)? + + /// Closure called on the `request(_:didParseResponse:)` event. + open var requestDidParseResponse: ((DataRequest, DataResponse) -> Void)? + + /// Closure called on the `request(_:didValidateRequest:response:withResult:)` event. + open var requestDidValidateRequestResponseWithResult: ((DataStreamRequest, URLRequest?, HTTPURLResponse, Request.ValidationResult) -> Void)? + + /// Closure called on the `request(_:didCreateUploadable:)` event. + open var requestDidCreateUploadable: ((UploadRequest, UploadRequest.Uploadable) -> Void)? + + /// Closure called on the `request(_:didFailToCreateUploadableWithError:)` event. + open var requestDidFailToCreateUploadableWithError: ((UploadRequest, AFError) -> Void)? + + /// Closure called on the `request(_:didProvideInputStream:)` event. + open var requestDidProvideInputStream: ((UploadRequest, InputStream) -> Void)? + + /// Closure called on the `request(_:didFinishDownloadingUsing:with:)` event. + open var requestDidFinishDownloadingUsingTaskWithResult: ((DownloadRequest, URLSessionTask, Result) -> Void)? + + /// Closure called on the `request(_:didCreateDestinationURL:)` event. + open var requestDidCreateDestinationURL: ((DownloadRequest, URL) -> Void)? + + /// Closure called on the `request(_:didValidateRequest:response:temporaryURL:destinationURL:withResult:)` event. + open var requestDidValidateRequestResponseFileURLWithResult: ((DownloadRequest, URLRequest?, HTTPURLResponse, URL?, Request.ValidationResult) -> Void)? + + /// Closure called on the `request(_:didParseResponse:)` event. + open var requestDidParseDownloadResponse: ((DownloadRequest, DownloadResponse) -> Void)? + + public let queue: DispatchQueue + + /// Creates an instance using the provided queue. + /// + /// - Parameter queue: `DispatchQueue` on which events will fired. `.main` by default. + public init(queue: DispatchQueue = .main) { + self.queue = queue + } + + open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) { + sessionDidBecomeInvalidWithError?(session, error) + } + + open func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge) { + taskDidReceiveChallenge?(session, task, challenge) + } + + open func urlSession(_ session: URLSession, + task: URLSessionTask, + didSendBodyData bytesSent: Int64, + totalBytesSent: Int64, + totalBytesExpectedToSend: Int64) { + taskDidSendBodyData?(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend) + } + + open func urlSession(_ session: URLSession, taskNeedsNewBodyStream task: URLSessionTask) { + taskNeedNewBodyStream?(session, task) + } + + open func urlSession(_ session: URLSession, + task: URLSessionTask, + willPerformHTTPRedirection response: HTTPURLResponse, + newRequest request: URLRequest) { + taskWillPerformHTTPRedirection?(session, task, response, request) + } + + open func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) { + taskDidFinishCollectingMetrics?(session, task, metrics) + } + + open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { + taskDidComplete?(session, task, error) + } + + open func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) { + taskIsWaitingForConnectivity?(session, task) + } + + open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { + dataTaskDidReceiveData?(session, dataTask, data) + } + + open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, willCacheResponse proposedResponse: CachedURLResponse) { + dataTaskWillCacheResponse?(session, dataTask, proposedResponse) + } + + open func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didResumeAtOffset fileOffset: Int64, + expectedTotalBytes: Int64) { + downloadTaskDidResumeAtOffset?(session, downloadTask, fileOffset, expectedTotalBytes) + } + + open func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didWriteData bytesWritten: Int64, + totalBytesWritten: Int64, + totalBytesExpectedToWrite: Int64) { + downloadTaskDidWriteData?(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) + } + + open func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { + downloadTaskDidFinishDownloadingToURL?(session, downloadTask, location) + } + + // MARK: Request Events + + open func request(_ request: Request, didCreateInitialURLRequest urlRequest: URLRequest) { + requestDidCreateInitialURLRequest?(request, urlRequest) + } + + open func request(_ request: Request, didFailToCreateURLRequestWithError error: AFError) { + requestDidFailToCreateURLRequestWithError?(request, error) + } + + open func request(_ request: Request, didAdaptInitialRequest initialRequest: URLRequest, to adaptedRequest: URLRequest) { + requestDidAdaptInitialRequestToAdaptedRequest?(request, initialRequest, adaptedRequest) + } + + open func request(_ request: Request, didFailToAdaptURLRequest initialRequest: URLRequest, withError error: AFError) { + requestDidFailToAdaptURLRequestWithError?(request, initialRequest, error) + } + + open func request(_ request: Request, didCreateURLRequest urlRequest: URLRequest) { + requestDidCreateURLRequest?(request, urlRequest) + } + + open func request(_ request: Request, didCreateTask task: URLSessionTask) { + requestDidCreateTask?(request, task) + } + + open func request(_ request: Request, didGatherMetrics metrics: URLSessionTaskMetrics) { + requestDidGatherMetrics?(request, metrics) + } + + open func request(_ request: Request, didFailTask task: URLSessionTask, earlyWithError error: AFError) { + requestDidFailTaskEarlyWithError?(request, task, error) + } + + open func request(_ request: Request, didCompleteTask task: URLSessionTask, with error: AFError?) { + requestDidCompleteTaskWithError?(request, task, error) + } + + open func requestIsRetrying(_ request: Request) { + requestIsRetrying?(request) + } + + open func requestDidFinish(_ request: Request) { + requestDidFinish?(request) + } + + open func requestDidResume(_ request: Request) { + requestDidResume?(request) + } + + public func request(_ request: Request, didResumeTask task: URLSessionTask) { + requestDidResumeTask?(request, task) + } + + open func requestDidSuspend(_ request: Request) { + requestDidSuspend?(request) + } + + public func request(_ request: Request, didSuspendTask task: URLSessionTask) { + requestDidSuspendTask?(request, task) + } + + open func requestDidCancel(_ request: Request) { + requestDidCancel?(request) + } + + public func request(_ request: Request, didCancelTask task: URLSessionTask) { + requestDidCancelTask?(request, task) + } + + open func request(_ request: DataRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + data: Data?, + withResult result: Request.ValidationResult) { + requestDidValidateRequestResponseDataWithResult?(request, urlRequest, response, data, result) + } + + open func request(_ request: DataRequest, didParseResponse response: DataResponse) { + requestDidParseResponse?(request, response) + } + + public func request(_ request: DataStreamRequest, didValidateRequest urlRequest: URLRequest?, response: HTTPURLResponse, withResult result: Request.ValidationResult) { + requestDidValidateRequestResponseWithResult?(request, urlRequest, response, result) + } + + open func request(_ request: UploadRequest, didCreateUploadable uploadable: UploadRequest.Uploadable) { + requestDidCreateUploadable?(request, uploadable) + } + + open func request(_ request: UploadRequest, didFailToCreateUploadableWithError error: AFError) { + requestDidFailToCreateUploadableWithError?(request, error) + } + + open func request(_ request: UploadRequest, didProvideInputStream stream: InputStream) { + requestDidProvideInputStream?(request, stream) + } + + open func request(_ request: DownloadRequest, didFinishDownloadingUsing task: URLSessionTask, with result: Result) { + requestDidFinishDownloadingUsingTaskWithResult?(request, task, result) + } + + open func request(_ request: DownloadRequest, didCreateDestinationURL url: URL) { + requestDidCreateDestinationURL?(request, url) + } + + open func request(_ request: DownloadRequest, + didValidateRequest urlRequest: URLRequest?, + response: HTTPURLResponse, + fileURL: URL?, + withResult result: Request.ValidationResult) { + requestDidValidateRequestResponseFileURLWithResult?(request, + urlRequest, + response, + fileURL, + result) + } + + open func request(_ request: DownloadRequest, didParseResponse response: DownloadResponse) { + requestDidParseDownloadResponse?(request, response) + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/HTTPHeaders.swift b/Instagram-Clone/Pods/Alamofire/Source/HTTPHeaders.swift new file mode 100644 index 0000000..cdbdbc6 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/HTTPHeaders.swift @@ -0,0 +1,447 @@ +// +// HTTPHeaders.swift +// +// Copyright (c) 2014-2018 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 + +/// An order-preserving and case-insensitive representation of HTTP headers. +public struct HTTPHeaders { + private var headers: [HTTPHeader] = [] + + /// Creates an empty instance. + public init() {} + + /// Creates an instance from an array of `HTTPHeader`s. Duplicate case-insensitive names are collapsed into the last + /// name and value encountered. + public init(_ headers: [HTTPHeader]) { + self.init() + + headers.forEach { update($0) } + } + + /// Creates an instance from a `[String: String]`. Duplicate case-insensitive names are collapsed into the last name + /// and value encountered. + public init(_ dictionary: [String: String]) { + self.init() + + dictionary.forEach { update(HTTPHeader(name: $0.key, value: $0.value)) } + } + + /// Case-insensitively updates or appends an `HTTPHeader` into the instance using the provided `name` and `value`. + /// + /// - Parameters: + /// - name: The `HTTPHeader` name. + /// - value: The `HTTPHeader value. + public mutating func add(name: String, value: String) { + update(HTTPHeader(name: name, value: value)) + } + + /// Case-insensitively updates or appends the provided `HTTPHeader` into the instance. + /// + /// - Parameter header: The `HTTPHeader` to update or append. + public mutating func add(_ header: HTTPHeader) { + update(header) + } + + /// Case-insensitively updates or appends an `HTTPHeader` into the instance using the provided `name` and `value`. + /// + /// - Parameters: + /// - name: The `HTTPHeader` name. + /// - value: The `HTTPHeader value. + public mutating func update(name: String, value: String) { + update(HTTPHeader(name: name, value: value)) + } + + /// Case-insensitively updates or appends the provided `HTTPHeader` into the instance. + /// + /// - Parameter header: The `HTTPHeader` to update or append. + public mutating func update(_ header: HTTPHeader) { + guard let index = headers.index(of: header.name) else { + headers.append(header) + return + } + + headers.replaceSubrange(index...index, with: [header]) + } + + /// Case-insensitively removes an `HTTPHeader`, if it exists, from the instance. + /// + /// - Parameter name: The name of the `HTTPHeader` to remove. + public mutating func remove(name: String) { + guard let index = headers.index(of: name) else { return } + + headers.remove(at: index) + } + + /// Sort the current instance by header name, case insensitively. + public mutating func sort() { + headers.sort { $0.name.lowercased() < $1.name.lowercased() } + } + + /// Returns an instance sorted by header name. + /// + /// - Returns: A copy of the current instance sorted by name. + public func sorted() -> HTTPHeaders { + var headers = self + headers.sort() + + return headers + } + + /// Case-insensitively find a header's value by name. + /// + /// - Parameter name: The name of the header to search for, case-insensitively. + /// + /// - Returns: The value of header, if it exists. + public func value(for name: String) -> String? { + guard let index = headers.index(of: name) else { return nil } + + return headers[index].value + } + + /// Case-insensitively access the header with the given name. + /// + /// - Parameter name: The name of the header. + public subscript(_ name: String) -> String? { + get { value(for: name) } + set { + if let value = newValue { + update(name: name, value: value) + } else { + remove(name: name) + } + } + } + + /// The dictionary representation of all headers. + /// + /// This representation does not preserve the current order of the instance. + public var dictionary: [String: String] { + let namesAndValues = headers.map { ($0.name, $0.value) } + + return Dictionary(namesAndValues, uniquingKeysWith: { _, last in last }) + } +} + +extension HTTPHeaders: ExpressibleByDictionaryLiteral { + public init(dictionaryLiteral elements: (String, String)...) { + self.init() + + elements.forEach { update(name: $0.0, value: $0.1) } + } +} + +extension HTTPHeaders: ExpressibleByArrayLiteral { + public init(arrayLiteral elements: HTTPHeader...) { + self.init(elements) + } +} + +extension HTTPHeaders: Sequence { + public func makeIterator() -> IndexingIterator<[HTTPHeader]> { + headers.makeIterator() + } +} + +extension HTTPHeaders: Collection { + public var startIndex: Int { + headers.startIndex + } + + public var endIndex: Int { + headers.endIndex + } + + public subscript(position: Int) -> HTTPHeader { + headers[position] + } + + public func index(after i: Int) -> Int { + headers.index(after: i) + } +} + +extension HTTPHeaders: CustomStringConvertible { + public var description: String { + headers.map(\.description) + .joined(separator: "\n") + } +} + +// MARK: - HTTPHeader + +/// A representation of a single HTTP header's name / value pair. +public struct HTTPHeader: Hashable { + /// Name of the header. + public let name: String + + /// Value of the header. + public let value: String + + /// Creates an instance from the given `name` and `value`. + /// + /// - Parameters: + /// - name: The name of the header. + /// - value: The value of the header. + public init(name: String, value: String) { + self.name = name + self.value = value + } +} + +extension HTTPHeader: CustomStringConvertible { + public var description: String { + "\(name): \(value)" + } +} + +extension HTTPHeader { + /// Returns an `Accept` header. + /// + /// - Parameter value: The `Accept` value. + /// - Returns: The header. + public static func accept(_ value: String) -> HTTPHeader { + HTTPHeader(name: "Accept", value: value) + } + + /// Returns an `Accept-Charset` header. + /// + /// - Parameter value: The `Accept-Charset` value. + /// - Returns: The header. + public static func acceptCharset(_ value: String) -> HTTPHeader { + HTTPHeader(name: "Accept-Charset", value: value) + } + + /// Returns an `Accept-Language` header. + /// + /// Alamofire offers a default Accept-Language header that accumulates and encodes the system's preferred languages. + /// Use `HTTPHeader.defaultAcceptLanguage`. + /// + /// - Parameter value: The `Accept-Language` value. + /// + /// - Returns: The header. + public static func acceptLanguage(_ value: String) -> HTTPHeader { + HTTPHeader(name: "Accept-Language", value: value) + } + + /// Returns an `Accept-Encoding` header. + /// + /// Alamofire offers a default accept encoding value that provides the most common values. Use + /// `HTTPHeader.defaultAcceptEncoding`. + /// + /// - Parameter value: The `Accept-Encoding` value. + /// + /// - Returns: The header + public static func acceptEncoding(_ value: String) -> HTTPHeader { + HTTPHeader(name: "Accept-Encoding", value: value) + } + + /// Returns a `Basic` `Authorization` header using the `username` and `password` provided. + /// + /// - Parameters: + /// - username: The username of the header. + /// - password: The password of the header. + /// + /// - Returns: The header. + public static func authorization(username: String, password: String) -> HTTPHeader { + let credential = Data("\(username):\(password)".utf8).base64EncodedString() + + return authorization("Basic \(credential)") + } + + /// Returns a `Bearer` `Authorization` header using the `bearerToken` provided + /// + /// - Parameter bearerToken: The bearer token. + /// + /// - Returns: The header. + public static func authorization(bearerToken: String) -> HTTPHeader { + authorization("Bearer \(bearerToken)") + } + + /// Returns an `Authorization` header. + /// + /// Alamofire provides built-in methods to produce `Authorization` headers. For a Basic `Authorization` header use + /// `HTTPHeader.authorization(username:password:)`. For a Bearer `Authorization` header, use + /// `HTTPHeader.authorization(bearerToken:)`. + /// + /// - Parameter value: The `Authorization` value. + /// + /// - Returns: The header. + public static func authorization(_ value: String) -> HTTPHeader { + HTTPHeader(name: "Authorization", value: value) + } + + /// Returns a `Content-Disposition` header. + /// + /// - Parameter value: The `Content-Disposition` value. + /// + /// - Returns: The header. + public static func contentDisposition(_ value: String) -> HTTPHeader { + HTTPHeader(name: "Content-Disposition", value: value) + } + + /// Returns a `Content-Type` header. + /// + /// All Alamofire `ParameterEncoding`s and `ParameterEncoder`s set the `Content-Type` of the request, so it may not be necessary to manually + /// set this value. + /// + /// - Parameter value: The `Content-Type` value. + /// + /// - Returns: The header. + public static func contentType(_ value: String) -> HTTPHeader { + HTTPHeader(name: "Content-Type", value: value) + } + + /// Returns a `User-Agent` header. + /// + /// - Parameter value: The `User-Agent` value. + /// + /// - Returns: The header. + public static func userAgent(_ value: String) -> HTTPHeader { + HTTPHeader(name: "User-Agent", value: value) + } +} + +extension Array where Element == HTTPHeader { + /// Case-insensitively finds the index of an `HTTPHeader` with the provided name, if it exists. + func index(of name: String) -> Int? { + let lowercasedName = name.lowercased() + return firstIndex { $0.name.lowercased() == lowercasedName } + } +} + +// MARK: - Defaults + +extension HTTPHeaders { + /// The default set of `HTTPHeaders` used by Alamofire. Includes `Accept-Encoding`, `Accept-Language`, and + /// `User-Agent`. + public static let `default`: HTTPHeaders = [.defaultAcceptEncoding, + .defaultAcceptLanguage, + .defaultUserAgent] +} + +extension HTTPHeader { + /// Returns Alamofire's default `Accept-Encoding` header, appropriate for the encodings supported by particular OS + /// versions. + /// + /// See the [Accept-Encoding HTTP header documentation](https://tools.ietf.org/html/rfc7230#section-4.2.3) . + public static let defaultAcceptEncoding: HTTPHeader = { + let encodings: [String] + if #available(iOS 11.0, macOS 10.13, tvOS 11.0, watchOS 4.0, *) { + encodings = ["br", "gzip", "deflate"] + } else { + encodings = ["gzip", "deflate"] + } + + return .acceptEncoding(encodings.qualityEncoded()) + }() + + /// Returns Alamofire's default `Accept-Language` header, generated by querying `Locale` for the user's + /// `preferredLanguages`. + /// + /// See the [Accept-Language HTTP header documentation](https://tools.ietf.org/html/rfc7231#section-5.3.5). + public static let defaultAcceptLanguage: HTTPHeader = .acceptLanguage(Locale.preferredLanguages.prefix(6).qualityEncoded()) + + /// Returns Alamofire's default `User-Agent` header. + /// + /// See the [User-Agent header documentation](https://tools.ietf.org/html/rfc7231#section-5.5.3). + /// + /// Example: `iOS Example/1.0 (org.alamofire.iOS-Example; build:1; iOS 13.0.0) Alamofire/5.0.0` + public static let defaultUserAgent: HTTPHeader = { + let info = Bundle.main.infoDictionary + let executable = (info?["CFBundleExecutable"] as? String) ?? + (ProcessInfo.processInfo.arguments.first?.split(separator: "/").last.map(String.init)) ?? + "Unknown" + let bundle = info?["CFBundleIdentifier"] as? String ?? "Unknown" + let appVersion = info?["CFBundleShortVersionString"] as? String ?? "Unknown" + let appBuild = info?["CFBundleVersion"] 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) + #if targetEnvironment(macCatalyst) + return "macOS(Catalyst)" + #else + return "iOS" + #endif + #elseif os(watchOS) + return "watchOS" + #elseif os(tvOS) + return "tvOS" + #elseif os(macOS) + return "macOS" + #elseif os(Linux) + return "Linux" + #elseif os(Windows) + return "Windows" + #else + return "Unknown" + #endif + }() + + return "\(osName) \(versionString)" + }() + + let alamofireVersion = "Alamofire/\(version)" + + let userAgent = "\(executable)/\(appVersion) (\(bundle); build:\(appBuild); \(osNameVersion)) \(alamofireVersion)" + + return .userAgent(userAgent) + }() +} + +extension Collection where Element == String { + func qualityEncoded() -> String { + enumerated().map { index, encoding in + let quality = 1.0 - (Double(index) * 0.1) + return "\(encoding);q=\(quality)" + }.joined(separator: ", ") + } +} + +// MARK: - System Type Extensions + +extension URLRequest { + /// Returns `allHTTPHeaderFields` as `HTTPHeaders`. + public var headers: HTTPHeaders { + get { allHTTPHeaderFields.map(HTTPHeaders.init) ?? HTTPHeaders() } + set { allHTTPHeaderFields = newValue.dictionary } + } +} + +extension HTTPURLResponse { + /// Returns `allHeaderFields` as `HTTPHeaders`. + public var headers: HTTPHeaders { + (allHeaderFields as? [String: String]).map(HTTPHeaders.init) ?? HTTPHeaders() + } +} + +extension URLSessionConfiguration { + /// Returns `httpAdditionalHeaders` as `HTTPHeaders`. + public var headers: HTTPHeaders { + get { (httpAdditionalHeaders as? [String: String]).map(HTTPHeaders.init) ?? HTTPHeaders() } + set { httpAdditionalHeaders = newValue.dictionary } + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/HTTPMethod.swift b/Instagram-Clone/Pods/Alamofire/Source/HTTPMethod.swift new file mode 100644 index 0000000..4867c1e --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/HTTPMethod.swift @@ -0,0 +1,54 @@ +// +// HTTPMethod.swift +// +// Copyright (c) 2014-2018 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. +// + +/// Type representing HTTP methods. Raw `String` value is stored and compared case-sensitively, so +/// `HTTPMethod.get != HTTPMethod(rawValue: "get")`. +/// +/// See https://tools.ietf.org/html/rfc7231#section-4.3 +public struct HTTPMethod: RawRepresentable, Equatable, Hashable { + /// `CONNECT` method. + public static let connect = HTTPMethod(rawValue: "CONNECT") + /// `DELETE` method. + public static let delete = HTTPMethod(rawValue: "DELETE") + /// `GET` method. + public static let get = HTTPMethod(rawValue: "GET") + /// `HEAD` method. + public static let head = HTTPMethod(rawValue: "HEAD") + /// `OPTIONS` method. + public static let options = HTTPMethod(rawValue: "OPTIONS") + /// `PATCH` method. + public static let patch = HTTPMethod(rawValue: "PATCH") + /// `POST` method. + public static let post = HTTPMethod(rawValue: "POST") + /// `PUT` method. + public static let put = HTTPMethod(rawValue: "PUT") + /// `TRACE` method. + public static let trace = HTTPMethod(rawValue: "TRACE") + + public let rawValue: String + + public init(rawValue: String) { + self.rawValue = rawValue + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/MultipartFormData.swift b/Instagram-Clone/Pods/Alamofire/Source/MultipartFormData.swift new file mode 100644 index 0000000..8f72860 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/MultipartFormData.swift @@ -0,0 +1,557 @@ +// +// MultipartFormData.swift +// +// Copyright (c) 2014-2018 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 + + enum EncodingCharacters { + static let crlf = "\r\n" + } + + enum BoundaryGenerator { + enum BoundaryType { + case initial, encapsulated, final + } + + static func randomBoundary() -> String { + let first = UInt32.random(in: UInt32.min...UInt32.max) + let second = UInt32.random(in: UInt32.min...UInt32.max) + + return String(format: "alamofire.boundary.%08x%08x", first, second) + } + + 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 Data(boundaryText.utf8) + } + } + + 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 + + /// Default memory threshold used when encoding `MultipartFormData`, in bytes. + public static let encodingMemoryThreshold: UInt64 = 10_000_000 + + /// 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 { bodyParts.reduce(0) { $0 + $1.bodyContentLength } } + + /// The boundary used to separate the body parts in the encoded form data. + public let boundary: String + + let fileManager: FileManager + + private var bodyParts: [BodyPart] + private var bodyPartError: AFError? + private let streamBufferSize: Int + + // MARK: - Lifecycle + + /// Creates an instance. + /// + /// - Parameters: + /// - fileManager: `FileManager` to use for file operations, if needed. + /// - boundary: Boundary `String` used to separate body parts. + public init(fileManager: FileManager = .default, boundary: String? = nil) { + self.fileManager = fileManager + self.boundary = boundary ?? BoundaryGenerator.randomBoundary() + 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 + // + streamBufferSize = 1024 + } + + // MARK: - Body Parts + + /// Creates a body part from the data and appends it to the instance. + /// + /// 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 + /// + /// - Parameters: + /// - data: `Data` to encoding into the instance. + /// - name: Name to associate with the `Data` in the `Content-Disposition` HTTP header. + /// - fileName: Filename to associate with the `Data` in the `Content-Disposition` HTTP header. + /// - mimeType: MIME type to associate with the data in the `Content-Type` HTTP header. + public func append(_ data: Data, withName name: String, fileName: String? = nil, mimeType: String? = nil) { + 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 instance. + /// + /// 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. + /// + /// - Parameters: + /// - fileURL: `URL` of the file whose content will be encoded into the instance. + /// - name: 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 instance. + /// + /// 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 + /// + /// - Parameters: + /// - fileURL: `URL` of the file whose content will be encoded into the instance. + /// - name: Name to associate with the file content in the `Content-Disposition` HTTP header. + /// - fileName: Filename to associate with the file content in the `Content-Disposition` HTTP header. + /// - mimeType: 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? + //============================================================ + + #if !(os(Linux) || os(Windows)) + do { + let isReachable = try fileURL.checkPromisedItemIsReachable() + guard isReachable else { + setBodyPartError(withReason: .bodyPartFileNotReachable(at: fileURL)) + return + } + } catch { + setBodyPartError(withReason: .bodyPartFileNotReachableWithError(atURL: fileURL, error: error)) + return + } + #endif + + //============================================================ + // Check 3 - is file URL a directory? + //============================================================ + + var isDirectory: ObjCBool = false + let path = fileURL.path + + guard fileManager.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.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 instance. + /// + /// 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 + /// + /// - Parameters: + /// - stream: `InputStream` to encode into the instance. + /// - length: Length, in bytes, of the stream. + /// - name: Name to associate with the stream content in the `Content-Disposition` HTTP header. + /// - fileName: Filename to associate with the stream content in the `Content-Disposition` HTTP header. + /// - mimeType: 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 stream, length, and headers and appends it to the instance. + /// + /// The body part data will be encoded using the following format: + /// + /// - HTTP headers + /// - Encoded stream data + /// - Multipart form boundary + /// + /// - Parameters: + /// - stream: `InputStream` to encode into the instance. + /// - length: Length, in bytes, of the stream. + /// - headers: `HTTPHeaders` 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 appended body parts into a single `Data` value. + /// + /// - Note: 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 `writeEncodedData(to:))` method. + /// + /// - Returns: The encoded `Data`, if encoding is successful. + /// - Throws: An `AFError` if encoding encounters an error. + 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 all appended body parts to 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: File `URL` to which to write the form data. + /// - Throws: An `AFError` if encoding encounters an error. + public func writeEncodedData(to fileURL: URL) throws { + if let bodyPartError = bodyPartError { + throw bodyPartError + } + + if fileManager.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() } + + bodyParts.first?.hasInitialBoundary = true + bodyParts.last?.hasFinalBoundary = true + + for bodyPart in 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 { + let headerText = bodyPart.headers.map { "\($0.name): \($0.value)\(EncodingCharacters.crlf)" } + .joined() + + EncodingCharacters.crlf + + return Data(headerText.utf8) + } + + 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 + } + } + + guard UInt64(encoded.count) == bodyPart.bodyContentLength else { + let error = AFError.UnexpectedInputStreamLength(bytesExpected: bodyPart.bodyContentLength, + bytesRead: UInt64(encoded.count)) + throw AFError.multipartEncodingFailed(reason: .inputStreamReadFailed(error: error)) + } + + 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 !(os(Linux) || os(Windows)) + if + let id = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(), + let contentType = UTTypeCopyPreferredTagWithClass(id, kUTTagClassMIMEType)?.takeRetainedValue() { + return contentType as String + } + #endif + + return "application/octet-stream" + } + + // MARK: - Private - Content Headers + + private func contentHeaders(withName name: String, fileName: String? = nil, mimeType: String? = nil) -> HTTPHeaders { + var disposition = "form-data; name=\"\(name)\"" + if let fileName = fileName { disposition += "; filename=\"\(fileName)\"" } + + var headers: HTTPHeaders = [.contentDisposition(disposition)] + if let mimeType = mimeType { headers.add(.contentType(mimeType)) } + + return headers + } + + // MARK: - Private - Boundary Encoding + + private func initialBoundaryData() -> Data { + BoundaryGenerator.boundaryData(forBoundaryType: .initial, boundary: boundary) + } + + private func encapsulatedBoundaryData() -> Data { + BoundaryGenerator.boundaryData(forBoundaryType: .encapsulated, boundary: boundary) + } + + private func finalBoundaryData() -> Data { + 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/Instagram-Clone/Pods/Alamofire/Source/MultipartUpload.swift b/Instagram-Clone/Pods/Alamofire/Source/MultipartUpload.swift new file mode 100644 index 0000000..ceda21f --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/MultipartUpload.swift @@ -0,0 +1,89 @@ +// +// MultipartUpload.swift +// +// Copyright (c) 2014-2018 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 + +/// Internal type which encapsulates a `MultipartFormData` upload. +final class MultipartUpload { + lazy var result = Result { try build() } + + @Protected + private(set) var multipartFormData: MultipartFormData + let encodingMemoryThreshold: UInt64 + let request: URLRequestConvertible + let fileManager: FileManager + + init(encodingMemoryThreshold: UInt64, + request: URLRequestConvertible, + multipartFormData: MultipartFormData) { + self.encodingMemoryThreshold = encodingMemoryThreshold + self.request = request + fileManager = multipartFormData.fileManager + self.multipartFormData = multipartFormData + } + + func build() throws -> UploadRequest.Uploadable { + let uploadable: UploadRequest.Uploadable + if $multipartFormData.contentLength < encodingMemoryThreshold { + let data = try $multipartFormData.read { try $0.encode() } + + uploadable = .data(data) + } else { + let tempDirectoryURL = fileManager.temporaryDirectory + let directoryURL = tempDirectoryURL.appendingPathComponent("org.alamofire.manager/multipart.form.data") + let fileName = UUID().uuidString + let fileURL = directoryURL.appendingPathComponent(fileName) + + try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil) + + do { + try $multipartFormData.read { try $0.writeEncodedData(to: fileURL) } + } catch { + // Cleanup after attempted write if it fails. + try? fileManager.removeItem(at: fileURL) + throw error + } + + uploadable = .file(fileURL, shouldRemove: true) + } + + return uploadable + } +} + +extension MultipartUpload: UploadConvertible { + func asURLRequest() throws -> URLRequest { + var urlRequest = try request.asURLRequest() + + $multipartFormData.read { multipartFormData in + urlRequest.headers.add(.contentType(multipartFormData.contentType)) + } + + return urlRequest + } + + func createUploadable() throws -> UploadRequest.Uploadable { + try result.get() + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/NetworkReachabilityManager.swift b/Instagram-Clone/Pods/Alamofire/Source/NetworkReachabilityManager.swift new file mode 100644 index 0000000..deeb3a4 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/NetworkReachabilityManager.swift @@ -0,0 +1,267 @@ +// +// NetworkReachabilityManager.swift +// +// Copyright (c) 2014-2018 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) || os(Linux) || os(Windows)) + +import Foundation +import SystemConfiguration + +/// The `NetworkReachabilityManager` class listens for reachability changes of hosts and addresses for both cellular 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. + public enum NetworkReachabilityStatus { + /// It is unknown whether the network is reachable. + case unknown + /// The network is not reachable. + case notReachable + /// The network is reachable on the associated `ConnectionType`. + case reachable(ConnectionType) + + init(_ flags: SCNetworkReachabilityFlags) { + guard flags.isActuallyReachable else { self = .notReachable; return } + + var networkStatus: NetworkReachabilityStatus = .reachable(.ethernetOrWiFi) + + if flags.isCellular { networkStatus = .reachable(.cellular) } + + self = networkStatus + } + + /// Defines the various connection types detected by reachability flags. + public enum ConnectionType { + /// The connection type is either over Ethernet or WiFi. + case ethernetOrWiFi + /// The connection type is a cellular connection. + case cellular + } + } + + /// A closure executed when the network reachability status changes. The closure takes a single argument: the + /// network reachability status. + public typealias Listener = (NetworkReachabilityStatus) -> Void + + /// Default `NetworkReachabilityManager` for the zero address and a `listenerQueue` of `.main`. + public static let `default` = NetworkReachabilityManager() + + // MARK: - Properties + + /// Whether the network is currently reachable. + open var isReachable: Bool { isReachableOnCellular || isReachableOnEthernetOrWiFi } + + /// Whether the network is currently reachable over the cellular interface. + /// + /// - Note: Using this property to decide whether to make a high or low bandwidth request is not recommended. + /// Instead, set the `allowsCellularAccess` on any `URLRequest`s being issued. + /// + open var isReachableOnCellular: Bool { status == .reachable(.cellular) } + + /// Whether the network is currently reachable over Ethernet or WiFi interface. + open var isReachableOnEthernetOrWiFi: Bool { status == .reachable(.ethernetOrWiFi) } + + /// `DispatchQueue` on which reachability will update. + public let reachabilityQueue = DispatchQueue(label: "org.alamofire.reachabilityQueue") + + /// Flags of the current reachability type, if any. + open var flags: SCNetworkReachabilityFlags? { + var flags = SCNetworkReachabilityFlags() + + return (SCNetworkReachabilityGetFlags(reachability, &flags)) ? flags : nil + } + + /// The current network reachability status. + open var status: NetworkReachabilityStatus { + flags.map(NetworkReachabilityStatus.init) ?? .unknown + } + + /// Mutable state storage. + struct MutableState { + /// A closure executed when the network reachability status changes. + var listener: Listener? + /// `DispatchQueue` on which listeners will be called. + var listenerQueue: DispatchQueue? + /// Previously calculated status. + var previousStatus: NetworkReachabilityStatus? + } + + /// `SCNetworkReachability` instance providing notifications. + private let reachability: SCNetworkReachability + + /// Protected storage for mutable state. + @Protected + private var mutableState = MutableState() + + // MARK: - Initialization + + /// Creates an instance with the specified host. + /// + /// - Note: The `host` value must *not* contain a scheme, just the hostname. + /// + /// - Parameters: + /// - host: Host used to evaluate network reachability. Must *not* include the scheme (e.g. `https`). + public convenience init?(host: String) { + guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else { return nil } + + self.init(reachability: reachability) + } + + /// Creates an 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. + public convenience init?() { + var zero = sockaddr() + zero.sa_len = UInt8(MemoryLayout.size) + zero.sa_family = sa_family_t(AF_INET) + + guard let reachability = SCNetworkReachabilityCreateWithAddress(nil, &zero) else { return nil } + + self.init(reachability: reachability) + } + + private init(reachability: SCNetworkReachability) { + self.reachability = reachability + } + + deinit { + stopListening() + } + + // MARK: - Listening + + /// Starts listening for changes in network reachability status. + /// + /// - Note: Stops and removes any existing listener. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which to call the `listener` closure. `.main` by default. + /// - listener: `Listener` closure called when reachability changes. + /// + /// - Returns: `true` if listening was started successfully, `false` otherwise. + @discardableResult + open func startListening(onQueue queue: DispatchQueue = .main, + onUpdatePerforming listener: @escaping Listener) -> Bool { + stopListening() + + $mutableState.write { state in + state.listenerQueue = queue + state.listener = listener + } + + var context = SCNetworkReachabilityContext(version: 0, + info: Unmanaged.passUnretained(self).toOpaque(), + retain: nil, + release: nil, + copyDescription: nil) + let callback: SCNetworkReachabilityCallBack = { _, flags, info in + guard let info = info else { return } + + let instance = Unmanaged.fromOpaque(info).takeUnretainedValue() + instance.notifyListener(flags) + } + + let queueAdded = SCNetworkReachabilitySetDispatchQueue(reachability, reachabilityQueue) + let callbackAdded = SCNetworkReachabilitySetCallback(reachability, callback, &context) + + // Manually call listener to give initial state, since the framework may not. + if let currentFlags = flags { + reachabilityQueue.async { + self.notifyListener(currentFlags) + } + } + + return callbackAdded && queueAdded + } + + /// Stops listening for changes in network reachability status. + open func stopListening() { + SCNetworkReachabilitySetCallback(reachability, nil, nil) + SCNetworkReachabilitySetDispatchQueue(reachability, nil) + $mutableState.write { state in + state.listener = nil + state.listenerQueue = nil + state.previousStatus = nil + } + } + + // MARK: - Internal - Listener Notification + + /// Calls the `listener` closure of the `listenerQueue` if the computed status hasn't changed. + /// + /// - Note: Should only be called from the `reachabilityQueue`. + /// + /// - Parameter flags: `SCNetworkReachabilityFlags` to use to calculate the status. + func notifyListener(_ flags: SCNetworkReachabilityFlags) { + let newStatus = NetworkReachabilityStatus(flags) + + $mutableState.write { state in + guard state.previousStatus != newStatus else { return } + + state.previousStatus = newStatus + + let listener = state.listener + state.listenerQueue?.async { listener?(newStatus) } + } + } +} + +// MARK: - + +extension NetworkReachabilityManager.NetworkReachabilityStatus: Equatable {} + +extension SCNetworkReachabilityFlags { + var isReachable: Bool { contains(.reachable) } + var isConnectionRequired: Bool { contains(.connectionRequired) } + var canConnectAutomatically: Bool { contains(.connectionOnDemand) || contains(.connectionOnTraffic) } + var canConnectWithoutUserInteraction: Bool { canConnectAutomatically && !contains(.interventionRequired) } + var isActuallyReachable: Bool { isReachable && (!isConnectionRequired || canConnectWithoutUserInteraction) } + var isCellular: Bool { + #if os(iOS) || os(tvOS) + return contains(.isWWAN) + #else + return false + #endif + } + + /// Human readable `String` for all states, to help with debugging. + var readableDescription: String { + let W = isCellular ? "W" : "-" + let R = isReachable ? "R" : "-" + let c = isConnectionRequired ? "c" : "-" + let t = contains(.transientConnection) ? "t" : "-" + let i = contains(.interventionRequired) ? "i" : "-" + let C = contains(.connectionOnTraffic) ? "C" : "-" + let D = contains(.connectionOnDemand) ? "D" : "-" + let l = contains(.isLocalAddress) ? "l" : "-" + let d = contains(.isDirect) ? "d" : "-" + let a = contains(.connectionAutomatic) ? "a" : "-" + + return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)\(a)" + } +} +#endif diff --git a/Instagram-Clone/Pods/Alamofire/Source/Notifications.swift b/Instagram-Clone/Pods/Alamofire/Source/Notifications.swift new file mode 100644 index 0000000..66434b6 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/Notifications.swift @@ -0,0 +1,115 @@ +// +// Notifications.swift +// +// Copyright (c) 2014-2018 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 { + /// Posted when a `Request` is resumed. The `Notification` contains the resumed `Request`. + public static let didResumeNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didResume") + /// Posted when a `Request` is suspended. The `Notification` contains the suspended `Request`. + public static let didSuspendNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didSuspend") + /// Posted when a `Request` is cancelled. The `Notification` contains the cancelled `Request`. + public static let didCancelNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didCancel") + /// Posted when a `Request` is finished. The `Notification` contains the completed `Request`. + public static let didFinishNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didFinish") + + /// Posted when a `URLSessionTask` is resumed. The `Notification` contains the `Request` associated with the `URLSessionTask`. + public static let didResumeTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didResumeTask") + /// Posted when a `URLSessionTask` is suspended. The `Notification` contains the `Request` associated with the `URLSessionTask`. + public static let didSuspendTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didSuspendTask") + /// Posted when a `URLSessionTask` is cancelled. The `Notification` contains the `Request` associated with the `URLSessionTask`. + public static let didCancelTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didCancelTask") + /// Posted when a `URLSessionTask` is completed. The `Notification` contains the `Request` associated with the `URLSessionTask`. + public static let didCompleteTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didCompleteTask") +} + +// MARK: - + +extension Notification { + /// The `Request` contained by the instance's `userInfo`, `nil` otherwise. + public var request: Request? { + userInfo?[String.requestKey] as? Request + } + + /// Convenience initializer for a `Notification` containing a `Request` payload. + /// + /// - Parameters: + /// - name: The name of the notification. + /// - request: The `Request` payload. + init(name: Notification.Name, request: Request) { + self.init(name: name, object: nil, userInfo: [String.requestKey: request]) + } +} + +extension NotificationCenter { + /// Convenience function for posting notifications with `Request` payloads. + /// + /// - Parameters: + /// - name: The name of the notification. + /// - request: The `Request` payload. + func postNotification(named name: Notification.Name, with request: Request) { + let notification = Notification(name: name, request: request) + post(notification) + } +} + +extension String { + /// User info dictionary key representing the `Request` associated with the notification. + fileprivate static let requestKey = "org.alamofire.notification.key.request" +} + +/// `EventMonitor` that provides Alamofire's notifications. +public final class AlamofireNotifications: EventMonitor { + public func requestDidResume(_ request: Request) { + NotificationCenter.default.postNotification(named: Request.didResumeNotification, with: request) + } + + public func requestDidSuspend(_ request: Request) { + NotificationCenter.default.postNotification(named: Request.didSuspendNotification, with: request) + } + + public func requestDidCancel(_ request: Request) { + NotificationCenter.default.postNotification(named: Request.didCancelNotification, with: request) + } + + public func requestDidFinish(_ request: Request) { + NotificationCenter.default.postNotification(named: Request.didFinishNotification, with: request) + } + + public func request(_ request: Request, didResumeTask task: URLSessionTask) { + NotificationCenter.default.postNotification(named: Request.didResumeTaskNotification, with: request) + } + + public func request(_ request: Request, didSuspendTask task: URLSessionTask) { + NotificationCenter.default.postNotification(named: Request.didSuspendTaskNotification, with: request) + } + + public func request(_ request: Request, didCancelTask task: URLSessionTask) { + NotificationCenter.default.postNotification(named: Request.didCancelTaskNotification, with: request) + } + + public func request(_ request: Request, didCompleteTask task: URLSessionTask, with error: AFError?) { + NotificationCenter.default.postNotification(named: Request.didCompleteTaskNotification, with: request) + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/OperationQueue+Alamofire.swift b/Instagram-Clone/Pods/Alamofire/Source/OperationQueue+Alamofire.swift new file mode 100644 index 0000000..b06a0cc --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/OperationQueue+Alamofire.swift @@ -0,0 +1,49 @@ +// +// OperationQueue+Alamofire.swift +// +// Copyright (c) 2014-2018 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 OperationQueue { + /// Creates an instance using the provided parameters. + /// + /// - Parameters: + /// - qualityOfService: `QualityOfService` to be applied to the queue. `.default` by default. + /// - maxConcurrentOperationCount: Maximum concurrent operations. + /// `OperationQueue.defaultMaxConcurrentOperationCount` by default. + /// - underlyingQueue: Underlying `DispatchQueue`. `nil` by default. + /// - name: Name for the queue. `nil` by default. + /// - startSuspended: Whether the queue starts suspended. `false` by default. + convenience init(qualityOfService: QualityOfService = .default, + maxConcurrentOperationCount: Int = OperationQueue.defaultMaxConcurrentOperationCount, + underlyingQueue: DispatchQueue? = nil, + name: String? = nil, + startSuspended: Bool = false) { + self.init() + self.qualityOfService = qualityOfService + self.maxConcurrentOperationCount = maxConcurrentOperationCount + self.underlyingQueue = underlyingQueue + self.name = name + isSuspended = startSuspended + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/ParameterEncoder.swift b/Instagram-Clone/Pods/Alamofire/Source/ParameterEncoder.swift new file mode 100644 index 0000000..2263660 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/ParameterEncoder.swift @@ -0,0 +1,217 @@ +// +// ParameterEncoder.swift +// +// Copyright (c) 2014-2018 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 encode any `Encodable` type into a `URLRequest`. +public protocol ParameterEncoder { + /// Encode the provided `Encodable` parameters into `request`. + /// + /// - Parameters: + /// - parameters: The `Encodable` parameter value. + /// - request: The `URLRequest` into which to encode the parameters. + /// + /// - Returns: A `URLRequest` with the result of the encoding. + /// - Throws: An `Error` when encoding fails. For Alamofire provided encoders, this will be an instance of + /// `AFError.parameterEncoderFailed` with an associated `ParameterEncoderFailureReason`. + func encode(_ parameters: Parameters?, into request: URLRequest) throws -> URLRequest +} + +/// A `ParameterEncoder` that encodes types as JSON body data. +/// +/// If no `Content-Type` header is already set on the provided `URLRequest`s, it's set to `application/json`. +open class JSONParameterEncoder: ParameterEncoder { + /// Returns an encoder with default parameters. + public static var `default`: JSONParameterEncoder { JSONParameterEncoder() } + + /// Returns an encoder with `JSONEncoder.outputFormatting` set to `.prettyPrinted`. + public static var prettyPrinted: JSONParameterEncoder { + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted + + return JSONParameterEncoder(encoder: encoder) + } + + /// Returns an encoder with `JSONEncoder.outputFormatting` set to `.sortedKeys`. + @available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) + public static var sortedKeys: JSONParameterEncoder { + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + + return JSONParameterEncoder(encoder: encoder) + } + + /// `JSONEncoder` used to encode parameters. + public let encoder: JSONEncoder + + /// Creates an instance with the provided `JSONEncoder`. + /// + /// - Parameter encoder: The `JSONEncoder`. `JSONEncoder()` by default. + public init(encoder: JSONEncoder = JSONEncoder()) { + self.encoder = encoder + } + + open func encode(_ parameters: Parameters?, + into request: URLRequest) throws -> URLRequest { + guard let parameters = parameters else { return request } + + var request = request + + do { + let data = try encoder.encode(parameters) + request.httpBody = data + if request.headers["Content-Type"] == nil { + request.headers.update(.contentType("application/json")) + } + } catch { + throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) + } + + return request + } +} + +#if swift(>=5.5) +extension ParameterEncoder where Self == JSONParameterEncoder { + /// Provides a default `JSONParameterEncoder` instance. + public static var json: JSONParameterEncoder { JSONParameterEncoder() } + + /// Creates a `JSONParameterEncoder` using the provided `JSONEncoder`. + /// + /// - Parameter encoder: `JSONEncoder` used to encode parameters. `JSONEncoder()` by default. + /// - Returns: The `JSONParameterEncoder`. + public static func json(encoder: JSONEncoder = JSONEncoder()) -> JSONParameterEncoder { + JSONParameterEncoder(encoder: encoder) + } +} +#endif + +/// A `ParameterEncoder` that encodes types as URL-encoded query strings to be set on the URL or as body data, depending +/// on the `Destination` set. +/// +/// If no `Content-Type` header is already set on the provided `URLRequest`s, it will be set to +/// `application/x-www-form-urlencoded; charset=utf-8`. +/// +/// Encoding behavior can be customized by passing an instance of `URLEncodedFormEncoder` to the initializer. +open class URLEncodedFormParameterEncoder: ParameterEncoder { + /// Defines where the URL-encoded string should be set for each `URLRequest`. + public enum Destination { + /// Applies the encoded query string to any existing query string for `.get`, `.head`, and `.delete` request. + /// Sets it to the `httpBody` for all other methods. + case methodDependent + /// Applies the encoded query string to any existing query string from the `URLRequest`. + case queryString + /// Applies the encoded query string to the `httpBody` of the `URLRequest`. + case httpBody + + /// Determines whether the URL-encoded string should be applied to the `URLRequest`'s `url`. + /// + /// - Parameter method: The `HTTPMethod`. + /// + /// - Returns: Whether the URL-encoded string should be applied to a `URL`. + func encodesParametersInURL(for method: HTTPMethod) -> Bool { + switch self { + case .methodDependent: return [.get, .head, .delete].contains(method) + case .queryString: return true + case .httpBody: return false + } + } + } + + /// Returns an encoder with default parameters. + public static var `default`: URLEncodedFormParameterEncoder { URLEncodedFormParameterEncoder() } + + /// The `URLEncodedFormEncoder` to use. + public let encoder: URLEncodedFormEncoder + + /// The `Destination` for the URL-encoded string. + public let destination: Destination + + /// Creates an instance with the provided `URLEncodedFormEncoder` instance and `Destination` value. + /// + /// - Parameters: + /// - encoder: The `URLEncodedFormEncoder`. `URLEncodedFormEncoder()` by default. + /// - destination: The `Destination`. `.methodDependent` by default. + public init(encoder: URLEncodedFormEncoder = URLEncodedFormEncoder(), destination: Destination = .methodDependent) { + self.encoder = encoder + self.destination = destination + } + + open func encode(_ parameters: Parameters?, + into request: URLRequest) throws -> URLRequest { + guard let parameters = parameters else { return request } + + var request = request + + guard let url = request.url else { + throw AFError.parameterEncoderFailed(reason: .missingRequiredComponent(.url)) + } + + guard let method = request.method else { + let rawValue = request.method?.rawValue ?? "nil" + throw AFError.parameterEncoderFailed(reason: .missingRequiredComponent(.httpMethod(rawValue: rawValue))) + } + + if destination.encodesParametersInURL(for: method), + var components = URLComponents(url: url, resolvingAgainstBaseURL: false) { + let query: String = try Result { try encoder.encode(parameters) } + .mapError { AFError.parameterEncoderFailed(reason: .encoderFailed(error: $0)) }.get() + let newQueryString = [components.percentEncodedQuery, query].compactMap { $0 }.joinedWithAmpersands() + components.percentEncodedQuery = newQueryString.isEmpty ? nil : newQueryString + + guard let newURL = components.url else { + throw AFError.parameterEncoderFailed(reason: .missingRequiredComponent(.url)) + } + + request.url = newURL + } else { + if request.headers["Content-Type"] == nil { + request.headers.update(.contentType("application/x-www-form-urlencoded; charset=utf-8")) + } + + request.httpBody = try Result { try encoder.encode(parameters) } + .mapError { AFError.parameterEncoderFailed(reason: .encoderFailed(error: $0)) }.get() + } + + return request + } +} + +#if swift(>=5.5) +extension ParameterEncoder where Self == URLEncodedFormParameterEncoder { + /// Provides a default `URLEncodedFormParameterEncoder` instance. + public static var urlEncodedForm: URLEncodedFormParameterEncoder { URLEncodedFormParameterEncoder() } + + /// Creates a `URLEncodedFormParameterEncoder` with the provided encoder and destination. + /// + /// - Parameters: + /// - encoder: `URLEncodedFormEncoder` used to encode the parameters. `URLEncodedFormEncoder()` by default. + /// - destination: `Destination` to which to encode the parameters. `.methodDependent` by default. + /// - Returns: The `URLEncodedFormParameterEncoder`. + public static func urlEncodedForm(encoder: URLEncodedFormEncoder = URLEncodedFormEncoder(), + destination: URLEncodedFormParameterEncoder.Destination = .methodDependent) -> URLEncodedFormParameterEncoder { + URLEncodedFormParameterEncoder(encoder: encoder, destination: destination) + } +} +#endif diff --git a/Instagram-Clone/Pods/Alamofire/Source/ParameterEncoding.swift b/Instagram-Clone/Pods/Alamofire/Source/ParameterEncoding.swift new file mode 100644 index 0000000..e7fa452 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/ParameterEncoding.swift @@ -0,0 +1,321 @@ +// +// ParameterEncoding.swift +// +// Copyright (c) 2014-2018 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 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 `URLRequest` by encoding parameters and applying them on the passed request. + /// + /// - Parameters: + /// - urlRequest: `URLRequestConvertible` value onto which parameters will be encoded. + /// - parameters: `Parameters` to encode onto the request. + /// + /// - Returns: The encoded `URLRequest`. + /// - Throws: Any `Error` produced during parameter encoding. + 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. + public enum Destination { + /// 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. + case methodDependent + /// Sets or appends encoded query string result to existing query string. + case queryString + /// Sets encoded query string result as the HTTP body of the URL request. + case httpBody + + func encodesParametersInURL(for method: HTTPMethod) -> Bool { + switch self { + case .methodDependent: return [.get, .head, .delete].contains(method) + case .queryString: return true + case .httpBody: return false + } + } + } + + /// Configures how `Array` parameters are encoded. + public enum ArrayEncoding { + /// An empty set of square brackets is appended to the key for every value. This is the default behavior. + case brackets + /// No brackets are appended. The key is encoded as is. + case noBrackets + /// Brackets containing the item index are appended. This matches the jQuery and Node.js behavior. + case indexInBrackets + + func encode(key: String, atIndex index: Int) -> String { + switch self { + case .brackets: + return "\(key)[]" + case .noBrackets: + return key + case .indexInBrackets: + return "\(key)[\(index)]" + } + } + } + + /// Configures how `Bool` parameters are encoded. + public enum BoolEncoding { + /// Encode `true` as `1` and `false` as `0`. This is the default behavior. + case numeric + /// Encode `true` and `false` as string literals. + case 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 with a `.methodDependent` destination. + public static var `default`: URLEncoding { URLEncoding() } + + /// Returns a `URLEncoding` instance with a `.queryString` destination. + public static var queryString: URLEncoding { URLEncoding(destination: .queryString) } + + /// Returns a `URLEncoding` instance with an `.httpBody` destination. + public static var httpBody: URLEncoding { 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 an instance using the specified parameters. + /// + /// - Parameters: + /// - destination: `Destination` defining where the encoded query string will be applied. `.methodDependent` by + /// default. + /// - arrayEncoding: `ArrayEncoding` to use. `.brackets` by default. + /// - boolEncoding: `BoolEncoding` to use. `.numeric` by default. + public init(destination: Destination = .methodDependent, + arrayEncoding: ArrayEncoding = .brackets, + boolEncoding: BoolEncoding = .numeric) { + self.destination = destination + self.arrayEncoding = arrayEncoding + self.boolEncoding = boolEncoding + } + + // MARK: Encoding + + 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 = urlRequest.method, destination.encodesParametersInURL(for: 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.headers["Content-Type"] == nil { + urlRequest.headers.update(.contentType("application/x-www-form-urlencoded; charset=utf-8")) + } + + urlRequest.httpBody = Data(query(parameters).utf8) + } + + return urlRequest + } + + /// Creates a percent-escaped, URL encoded query string components from the given key-value pair recursively. + /// + /// - Parameters: + /// - key: Key of the query component. + /// - value: 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)] = [] + switch value { + case let dictionary as [String: Any]: + for (nestedKey, value) in dictionary { + components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value) + } + case let array as [Any]: + for (index, value) in array.enumerated() { + components += queryComponents(fromKey: arrayEncoding.encode(key: key, atIndex: index), value: value) + } + case let number as NSNumber: + if number.isBool { + components.append((escape(key), escape(boolEncoding.encode(value: number.boolValue)))) + } else { + components.append((escape(key), escape("\(number)"))) + } + case let bool as Bool: + components.append((escape(key), escape(boolEncoding.encode(value: bool)))) + default: + components.append((escape(key), escape("\(value)"))) + } + return components + } + + /// Creates a percent-escaped string following RFC 3986 for a query string key or value. + /// + /// - Parameter string: `String` to be percent-escaped. + /// + /// - Returns: The percent-escaped `String`. + public func escape(_ string: String) -> String { + string.addingPercentEncoding(withAllowedCharacters: .afURLQueryAllowed) ?? string + } + + private func query(_ parameters: [String: Any]) -> 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: "&") + } +} + +// 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 { JSONEncoding() } + + /// Returns a `JSONEncoding` instance with `.prettyPrinted` writing options. + public static var prettyPrinted: JSONEncoding { JSONEncoding(options: .prettyPrinted) } + + /// The options for writing the parameters as JSON data. + public let options: JSONSerialization.WritingOptions + + // MARK: Initialization + + /// Creates an instance using the specified `WritingOptions`. + /// + /// - Parameter options: `JSONSerialization.WritingOptions` to use. + public init(options: JSONSerialization.WritingOptions = []) { + self.options = options + } + + // MARK: Encoding + + 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.headers["Content-Type"] == nil { + urlRequest.headers.update(.contentType("application/json")) + } + + urlRequest.httpBody = data + } catch { + throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) + } + + return urlRequest + } + + /// Encodes any JSON compatible object into a `URLRequest`. + /// + /// - Parameters: + /// - urlRequest: `URLRequestConvertible` value into which the object will be encoded. + /// - jsonObject: `Any` value (must be JSON compatible` to be encoded into the `URLRequest`. `nil` by default. + /// + /// - Returns: The encoded `URLRequest`. + /// - Throws: Any `Error` produced during encoding. + 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.headers["Content-Type"] == nil { + urlRequest.headers.update(.contentType("application/json")) + } + + urlRequest.httpBody = data + } catch { + throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) + } + + return urlRequest + } +} + +// MARK: - + +extension NSNumber { + fileprivate var isBool: Bool { + // Use Obj-C type encoding to check whether the underlying type is a `Bool`, as it's guaranteed as part of + // swift-corelibs-foundation, per [this discussion on the Swift forums](https://forums.swift.org/t/alamofire-on-linux-possible-but-not-release-ready/34553/22). + String(cString: objCType) == "c" + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/Protected.swift b/Instagram-Clone/Pods/Alamofire/Source/Protected.swift new file mode 100644 index 0000000..2c056fa --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/Protected.swift @@ -0,0 +1,161 @@ +// +// Protected.swift +// +// Copyright (c) 2014-2020 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 + +private protocol Lock { + func lock() + func unlock() +} + +extension Lock { + /// Executes a closure returning a value while acquiring the lock. + /// + /// - Parameter closure: The closure to run. + /// + /// - Returns: The value the closure generated. + func around(_ closure: () throws -> T) rethrows -> T { + lock(); defer { unlock() } + return try closure() + } + + /// Execute a closure while acquiring the lock. + /// + /// - Parameter closure: The closure to run. + func around(_ closure: () throws -> Void) rethrows { + lock(); defer { unlock() } + try closure() + } +} + +#if os(Linux) || os(Windows) + +extension NSLock: Lock {} + +#endif + +#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) +/// An `os_unfair_lock` wrapper. +final class UnfairLock: Lock { + private let unfairLock: os_unfair_lock_t + + init() { + unfairLock = .allocate(capacity: 1) + unfairLock.initialize(to: os_unfair_lock()) + } + + deinit { + unfairLock.deinitialize(count: 1) + unfairLock.deallocate() + } + + fileprivate func lock() { + os_unfair_lock_lock(unfairLock) + } + + fileprivate func unlock() { + os_unfair_lock_unlock(unfairLock) + } +} +#endif + +/// A thread-safe wrapper around a value. +@propertyWrapper +@dynamicMemberLookup +final class Protected { + #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) + private let lock = UnfairLock() + #elseif os(Linux) || os(Windows) + private let lock = NSLock() + #endif + private var value: T + + init(_ value: T) { + self.value = value + } + + /// The contained value. Unsafe for anything more than direct read or write. + var wrappedValue: T { + get { lock.around { value } } + set { lock.around { value = newValue } } + } + + var projectedValue: Protected { self } + + init(wrappedValue: T) { + value = wrappedValue + } + + /// Synchronously read or transform the contained value. + /// + /// - Parameter closure: The closure to execute. + /// + /// - Returns: The return value of the closure passed. + func read(_ closure: (T) throws -> U) rethrows -> U { + try lock.around { try closure(self.value) } + } + + /// Synchronously modify the protected value. + /// + /// - Parameter closure: The closure to execute. + /// + /// - Returns: The modified value. + @discardableResult + func write(_ closure: (inout T) throws -> U) rethrows -> U { + try lock.around { try closure(&self.value) } + } + + subscript(dynamicMember keyPath: WritableKeyPath) -> Property { + get { lock.around { value[keyPath: keyPath] } } + set { lock.around { value[keyPath: keyPath] = newValue } } + } + + subscript(dynamicMember keyPath: KeyPath) -> Property { + lock.around { value[keyPath: keyPath] } + } +} + +extension Protected where T == Request.MutableState { + /// Attempts to transition to the passed `State`. + /// + /// - Parameter state: The `State` to attempt transition to. + /// + /// - Returns: Whether the transition occurred. + func attemptToTransitionTo(_ state: Request.State) -> Bool { + lock.around { + guard value.state.canTransitionTo(state) else { return false } + + value.state = state + + return true + } + } + + /// Perform a closure while locked with the provided `Request.State`. + /// + /// - Parameter perform: The closure to perform while locked. + func withState(perform: (Request.State) -> Void) { + lock.around { perform(value.state) } + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/RedirectHandler.swift b/Instagram-Clone/Pods/Alamofire/Source/RedirectHandler.swift new file mode 100644 index 0000000..5c232b8 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/RedirectHandler.swift @@ -0,0 +1,113 @@ +// +// RedirectHandler.swift +// +// Copyright (c) 2014-2018 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 handles how an HTTP redirect response from a remote server should be redirected to the new request. +public protocol RedirectHandler { + /// Determines how the HTTP redirect response should be redirected to the new request. + /// + /// The `completion` closure should be passed one of three possible options: + /// + /// 1. The new request specified by the redirect (this is the most common use case). + /// 2. A modified version of the new request (you may want to route it somewhere else). + /// 3. A `nil` value to deny the redirect request and return the body of the redirect response. + /// + /// - Parameters: + /// - task: The `URLSessionTask` whose request resulted in a redirect. + /// - request: The `URLRequest` to the new location specified by the redirect response. + /// - response: The `HTTPURLResponse` containing the server's response to the original request. + /// - completion: The closure to execute containing the new `URLRequest`, a modified `URLRequest`, or `nil`. + func task(_ task: URLSessionTask, + willBeRedirectedTo request: URLRequest, + for response: HTTPURLResponse, + completion: @escaping (URLRequest?) -> Void) +} + +// MARK: - + +/// `Redirector` is a convenience `RedirectHandler` making it easy to follow, not follow, or modify a redirect. +public struct Redirector { + /// Defines the behavior of the `Redirector` type. + public enum Behavior { + /// Follow the redirect as defined in the response. + case follow + /// Do not follow the redirect defined in the response. + case doNotFollow + /// Modify the redirect request defined in the response. + case modify((URLSessionTask, URLRequest, HTTPURLResponse) -> URLRequest?) + } + + /// Returns a `Redirector` with a `.follow` `Behavior`. + public static let follow = Redirector(behavior: .follow) + /// Returns a `Redirector` with a `.doNotFollow` `Behavior`. + public static let doNotFollow = Redirector(behavior: .doNotFollow) + + /// The `Behavior` of the `Redirector`. + public let behavior: Behavior + + /// Creates a `Redirector` instance from the `Behavior`. + /// + /// - Parameter behavior: The `Behavior`. + public init(behavior: Behavior) { + self.behavior = behavior + } +} + +// MARK: - + +extension Redirector: RedirectHandler { + public func task(_ task: URLSessionTask, + willBeRedirectedTo request: URLRequest, + for response: HTTPURLResponse, + completion: @escaping (URLRequest?) -> Void) { + switch behavior { + case .follow: + completion(request) + case .doNotFollow: + completion(nil) + case let .modify(closure): + let request = closure(task, request, response) + completion(request) + } + } +} + +#if swift(>=5.5) +extension RedirectHandler where Self == Redirector { + /// Provides a `Redirector` which follows redirects. Equivalent to `Redirector.follow`. + public static var follow: Redirector { .follow } + + /// Provides a `Redirector` which does not follow redirects. Equivalent to `Redirector.doNotFollow`. + public static var doNotFollow: Redirector { .doNotFollow } + + /// Creates a `Redirector` which modifies the redirected `URLRequest` using the provided closure. + /// + /// - Parameter closure: Closure used to modify the redirect. + /// - Returns: The `Redirector`. + public static func modify(using closure: @escaping (URLSessionTask, URLRequest, HTTPURLResponse) -> URLRequest?) -> Redirector { + Redirector(behavior: .modify(closure)) + } +} +#endif diff --git a/Instagram-Clone/Pods/Alamofire/Source/Request.swift b/Instagram-Clone/Pods/Alamofire/Source/Request.swift new file mode 100644 index 0000000..fdbdf11 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/Request.swift @@ -0,0 +1,1912 @@ +// +// Request.swift +// +// Copyright (c) 2014-2020 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 + +/// `Request` is the common superclass of all Alamofire request types and provides common state, delegate, and callback +/// handling. +public class Request { + /// State of the `Request`, with managed transitions between states set when calling `resume()`, `suspend()`, or + /// `cancel()` on the `Request`. + public enum State { + /// Initial state of the `Request`. + case initialized + /// `State` set when `resume()` is called. Any tasks created for the `Request` will have `resume()` called on + /// them in this state. + case resumed + /// `State` set when `suspend()` is called. Any tasks created for the `Request` will have `suspend()` called on + /// them in this state. + case suspended + /// `State` set when `cancel()` is called. Any tasks created for the `Request` will have `cancel()` called on + /// them. Unlike `resumed` or `suspended`, once in the `cancelled` state, the `Request` can no longer transition + /// to any other state. + case cancelled + /// `State` set when all response serialization completion closures have been cleared on the `Request` and + /// enqueued on their respective queues. + case finished + + /// Determines whether `self` can be transitioned to the provided `State`. + func canTransitionTo(_ state: State) -> Bool { + switch (self, state) { + case (.initialized, _): + return true + case (_, .initialized), (.cancelled, _), (.finished, _): + return false + case (.resumed, .cancelled), (.suspended, .cancelled), (.resumed, .suspended), (.suspended, .resumed): + return true + case (.suspended, .suspended), (.resumed, .resumed): + return false + case (_, .finished): + return true + } + } + } + + // MARK: - Initial State + + /// `UUID` providing a unique identifier for the `Request`, used in the `Hashable` and `Equatable` conformances. + public let id: UUID + /// The serial queue for all internal async actions. + public let underlyingQueue: DispatchQueue + /// The queue used for all serialization actions. By default it's a serial queue that targets `underlyingQueue`. + public let serializationQueue: DispatchQueue + /// `EventMonitor` used for event callbacks. + public let eventMonitor: EventMonitor? + /// The `Request`'s interceptor. + public let interceptor: RequestInterceptor? + /// The `Request`'s delegate. + public private(set) weak var delegate: RequestDelegate? + + // MARK: - Mutable State + + /// Type encapsulating all mutable state that may need to be accessed from anything other than the `underlyingQueue`. + struct MutableState { + /// State of the `Request`. + var state: State = .initialized + /// `ProgressHandler` and `DispatchQueue` provided for upload progress callbacks. + var uploadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)? + /// `ProgressHandler` and `DispatchQueue` provided for download progress callbacks. + var downloadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)? + /// `RedirectHandler` provided for to handle request redirection. + var redirectHandler: RedirectHandler? + /// `CachedResponseHandler` provided to handle response caching. + var cachedResponseHandler: CachedResponseHandler? + /// Queue and closure called when the `Request` is able to create a cURL description of itself. + var cURLHandler: (queue: DispatchQueue, handler: (String) -> Void)? + /// Queue and closure called when the `Request` creates a `URLRequest`. + var urlRequestHandler: (queue: DispatchQueue, handler: (URLRequest) -> Void)? + /// Queue and closure called when the `Request` creates a `URLSessionTask`. + var urlSessionTaskHandler: (queue: DispatchQueue, handler: (URLSessionTask) -> Void)? + /// Response serialization closures that handle response parsing. + var responseSerializers: [() -> Void] = [] + /// Response serialization completion closures executed once all response serializers are complete. + var responseSerializerCompletions: [() -> Void] = [] + /// Whether response serializer processing is finished. + var responseSerializerProcessingFinished = false + /// `URLCredential` used for authentication challenges. + var credential: URLCredential? + /// All `URLRequest`s created by Alamofire on behalf of the `Request`. + var requests: [URLRequest] = [] + /// All `URLSessionTask`s created by Alamofire on behalf of the `Request`. + var tasks: [URLSessionTask] = [] + /// All `URLSessionTaskMetrics` values gathered by Alamofire on behalf of the `Request`. Should correspond + /// exactly the the `tasks` created. + var metrics: [URLSessionTaskMetrics] = [] + /// Number of times any retriers provided retried the `Request`. + var retryCount = 0 + /// Final `AFError` for the `Request`, whether from various internal Alamofire calls or as a result of a `task`. + var error: AFError? + /// Whether the instance has had `finish()` called and is running the serializers. Should be replaced with a + /// representation in the state machine in the future. + var isFinishing = false + /// Actions to run when requests are finished. Use for concurrency support. + var finishHandlers: [() -> Void] = [] + } + + /// Protected `MutableState` value that provides thread-safe access to state values. + @Protected + fileprivate var mutableState = MutableState() + + /// `State` of the `Request`. + public var state: State { $mutableState.state } + /// Returns whether `state` is `.initialized`. + public var isInitialized: Bool { state == .initialized } + /// Returns whether `state is `.resumed`. + public var isResumed: Bool { state == .resumed } + /// Returns whether `state` is `.suspended`. + public var isSuspended: Bool { state == .suspended } + /// Returns whether `state` is `.cancelled`. + public var isCancelled: Bool { state == .cancelled } + /// Returns whether `state` is `.finished`. + public var isFinished: Bool { state == .finished } + + // MARK: Progress + + /// Closure type executed when monitoring the upload or download progress of a request. + public typealias ProgressHandler = (Progress) -> Void + + /// `Progress` of the upload of the body of the executed `URLRequest`. Reset to `0` if the `Request` is retried. + public let uploadProgress = Progress(totalUnitCount: 0) + /// `Progress` of the download of any response data. Reset to `0` if the `Request` is retried. + public let downloadProgress = Progress(totalUnitCount: 0) + /// `ProgressHandler` called when `uploadProgress` is updated, on the provided `DispatchQueue`. + private var uploadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)? { + get { $mutableState.uploadProgressHandler } + set { $mutableState.uploadProgressHandler = newValue } + } + + /// `ProgressHandler` called when `downloadProgress` is updated, on the provided `DispatchQueue`. + fileprivate var downloadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)? { + get { $mutableState.downloadProgressHandler } + set { $mutableState.downloadProgressHandler = newValue } + } + + // MARK: Redirect Handling + + /// `RedirectHandler` set on the instance. + public private(set) var redirectHandler: RedirectHandler? { + get { $mutableState.redirectHandler } + set { $mutableState.redirectHandler = newValue } + } + + // MARK: Cached Response Handling + + /// `CachedResponseHandler` set on the instance. + public private(set) var cachedResponseHandler: CachedResponseHandler? { + get { $mutableState.cachedResponseHandler } + set { $mutableState.cachedResponseHandler = newValue } + } + + // MARK: URLCredential + + /// `URLCredential` used for authentication challenges. Created by calling one of the `authenticate` methods. + public private(set) var credential: URLCredential? { + get { $mutableState.credential } + set { $mutableState.credential = newValue } + } + + // MARK: Validators + + /// `Validator` callback closures that store the validation calls enqueued. + @Protected + fileprivate var validators: [() -> Void] = [] + + // MARK: URLRequests + + /// All `URLRequests` created on behalf of the `Request`, including original and adapted requests. + public var requests: [URLRequest] { $mutableState.requests } + /// First `URLRequest` created on behalf of the `Request`. May not be the first one actually executed. + public var firstRequest: URLRequest? { requests.first } + /// Last `URLRequest` created on behalf of the `Request`. + public var lastRequest: URLRequest? { requests.last } + /// Current `URLRequest` created on behalf of the `Request`. + public var request: URLRequest? { lastRequest } + + /// `URLRequest`s from all of the `URLSessionTask`s executed on behalf of the `Request`. May be different from + /// `requests` due to `URLSession` manipulation. + public var performedRequests: [URLRequest] { $mutableState.read { $0.tasks.compactMap(\.currentRequest) } } + + // MARK: HTTPURLResponse + + /// `HTTPURLResponse` received from the server, if any. If the `Request` was retried, this is the response of the + /// last `URLSessionTask`. + public var response: HTTPURLResponse? { lastTask?.response as? HTTPURLResponse } + + // MARK: Tasks + + /// All `URLSessionTask`s created on behalf of the `Request`. + public var tasks: [URLSessionTask] { $mutableState.tasks } + /// First `URLSessionTask` created on behalf of the `Request`. + public var firstTask: URLSessionTask? { tasks.first } + /// Last `URLSessionTask` crated on behalf of the `Request`. + public var lastTask: URLSessionTask? { tasks.last } + /// Current `URLSessionTask` created on behalf of the `Request`. + public var task: URLSessionTask? { lastTask } + + // MARK: Metrics + + /// All `URLSessionTaskMetrics` gathered on behalf of the `Request`. Should correspond to the `tasks` created. + public var allMetrics: [URLSessionTaskMetrics] { $mutableState.metrics } + /// First `URLSessionTaskMetrics` gathered on behalf of the `Request`. + public var firstMetrics: URLSessionTaskMetrics? { allMetrics.first } + /// Last `URLSessionTaskMetrics` gathered on behalf of the `Request`. + public var lastMetrics: URLSessionTaskMetrics? { allMetrics.last } + /// Current `URLSessionTaskMetrics` gathered on behalf of the `Request`. + public var metrics: URLSessionTaskMetrics? { lastMetrics } + + // MARK: Retry Count + + /// Number of times the `Request` has been retried. + public var retryCount: Int { $mutableState.retryCount } + + // MARK: Error + + /// `Error` returned from Alamofire internally, from the network request directly, or any validators executed. + public fileprivate(set) var error: AFError? { + get { $mutableState.error } + set { $mutableState.error = newValue } + } + + /// Default initializer for the `Request` superclass. + /// + /// - Parameters: + /// - id: `UUID` used for the `Hashable` and `Equatable` implementations. `UUID()` by default. + /// - underlyingQueue: `DispatchQueue` on which all internal `Request` work is performed. + /// - serializationQueue: `DispatchQueue` on which all serialization work is performed. By default targets + /// `underlyingQueue`, but can be passed another queue from a `Session`. + /// - eventMonitor: `EventMonitor` called for event callbacks from internal `Request` actions. + /// - interceptor: `RequestInterceptor` used throughout the request lifecycle. + /// - delegate: `RequestDelegate` that provides an interface to actions not performed by the `Request`. + init(id: UUID = UUID(), + underlyingQueue: DispatchQueue, + serializationQueue: DispatchQueue, + eventMonitor: EventMonitor?, + interceptor: RequestInterceptor?, + delegate: RequestDelegate) { + self.id = id + self.underlyingQueue = underlyingQueue + self.serializationQueue = serializationQueue + self.eventMonitor = eventMonitor + self.interceptor = interceptor + self.delegate = delegate + } + + // MARK: - Internal Event API + + // All API must be called from underlyingQueue. + + /// Called when an initial `URLRequest` has been created on behalf of the instance. If a `RequestAdapter` is active, + /// the `URLRequest` will be adapted before being issued. + /// + /// - Parameter request: The `URLRequest` created. + func didCreateInitialURLRequest(_ request: URLRequest) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + $mutableState.write { $0.requests.append(request) } + + eventMonitor?.request(self, didCreateInitialURLRequest: request) + } + + /// Called when initial `URLRequest` creation has failed, typically through a `URLRequestConvertible`. + /// + /// - Note: Triggers retry. + /// + /// - Parameter error: `AFError` thrown from the failed creation. + func didFailToCreateURLRequest(with error: AFError) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + self.error = error + + eventMonitor?.request(self, didFailToCreateURLRequestWithError: error) + + callCURLHandlerIfNecessary() + + retryOrFinish(error: error) + } + + /// Called when a `RequestAdapter` has successfully adapted a `URLRequest`. + /// + /// - Parameters: + /// - initialRequest: The `URLRequest` that was adapted. + /// - adaptedRequest: The `URLRequest` returned by the `RequestAdapter`. + func didAdaptInitialRequest(_ initialRequest: URLRequest, to adaptedRequest: URLRequest) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + $mutableState.write { $0.requests.append(adaptedRequest) } + + eventMonitor?.request(self, didAdaptInitialRequest: initialRequest, to: adaptedRequest) + } + + /// Called when a `RequestAdapter` fails to adapt a `URLRequest`. + /// + /// - Note: Triggers retry. + /// + /// - Parameters: + /// - request: The `URLRequest` the adapter was called with. + /// - error: The `AFError` returned by the `RequestAdapter`. + func didFailToAdaptURLRequest(_ request: URLRequest, withError error: AFError) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + self.error = error + + eventMonitor?.request(self, didFailToAdaptURLRequest: request, withError: error) + + callCURLHandlerIfNecessary() + + retryOrFinish(error: error) + } + + /// Final `URLRequest` has been created for the instance. + /// + /// - Parameter request: The `URLRequest` created. + func didCreateURLRequest(_ request: URLRequest) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + $mutableState.read { state in + state.urlRequestHandler?.queue.async { state.urlRequestHandler?.handler(request) } + } + + eventMonitor?.request(self, didCreateURLRequest: request) + + callCURLHandlerIfNecessary() + } + + /// Asynchronously calls any stored `cURLHandler` and then removes it from `mutableState`. + private func callCURLHandlerIfNecessary() { + $mutableState.write { mutableState in + guard let cURLHandler = mutableState.cURLHandler else { return } + + cURLHandler.queue.async { cURLHandler.handler(self.cURLDescription()) } + + mutableState.cURLHandler = nil + } + } + + /// Called when a `URLSessionTask` is created on behalf of the instance. + /// + /// - Parameter task: The `URLSessionTask` created. + func didCreateTask(_ task: URLSessionTask) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + $mutableState.write { state in + state.tasks.append(task) + + guard let urlSessionTaskHandler = state.urlSessionTaskHandler else { return } + + urlSessionTaskHandler.queue.async { urlSessionTaskHandler.handler(task) } + } + + eventMonitor?.request(self, didCreateTask: task) + } + + /// Called when resumption is completed. + func didResume() { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + eventMonitor?.requestDidResume(self) + } + + /// Called when a `URLSessionTask` is resumed on behalf of the instance. + /// + /// - Parameter task: The `URLSessionTask` resumed. + func didResumeTask(_ task: URLSessionTask) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + eventMonitor?.request(self, didResumeTask: task) + } + + /// Called when suspension is completed. + func didSuspend() { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + eventMonitor?.requestDidSuspend(self) + } + + /// Called when a `URLSessionTask` is suspended on behalf of the instance. + /// + /// - Parameter task: The `URLSessionTask` suspended. + func didSuspendTask(_ task: URLSessionTask) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + eventMonitor?.request(self, didSuspendTask: task) + } + + /// Called when cancellation is completed, sets `error` to `AFError.explicitlyCancelled`. + func didCancel() { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + error = error ?? AFError.explicitlyCancelled + + eventMonitor?.requestDidCancel(self) + } + + /// Called when a `URLSessionTask` is cancelled on behalf of the instance. + /// + /// - Parameter task: The `URLSessionTask` cancelled. + func didCancelTask(_ task: URLSessionTask) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + eventMonitor?.request(self, didCancelTask: task) + } + + /// Called when a `URLSessionTaskMetrics` value is gathered on behalf of the instance. + /// + /// - Parameter metrics: The `URLSessionTaskMetrics` gathered. + func didGatherMetrics(_ metrics: URLSessionTaskMetrics) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + $mutableState.write { $0.metrics.append(metrics) } + + eventMonitor?.request(self, didGatherMetrics: metrics) + } + + /// Called when a `URLSessionTask` fails before it is finished, typically during certificate pinning. + /// + /// - Parameters: + /// - task: The `URLSessionTask` which failed. + /// - error: The early failure `AFError`. + func didFailTask(_ task: URLSessionTask, earlyWithError error: AFError) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + self.error = error + + // Task will still complete, so didCompleteTask(_:with:) will handle retry. + eventMonitor?.request(self, didFailTask: task, earlyWithError: error) + } + + /// Called when a `URLSessionTask` completes. All tasks will eventually call this method. + /// + /// - Note: Response validation is synchronously triggered in this step. + /// + /// - Parameters: + /// - task: The `URLSessionTask` which completed. + /// - error: The `AFError` `task` may have completed with. If `error` has already been set on the instance, this + /// value is ignored. + func didCompleteTask(_ task: URLSessionTask, with error: AFError?) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + self.error = self.error ?? error + + validators.forEach { $0() } + + eventMonitor?.request(self, didCompleteTask: task, with: error) + + retryOrFinish(error: self.error) + } + + /// Called when the `RequestDelegate` is going to retry this `Request`. Calls `reset()`. + func prepareForRetry() { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + $mutableState.write { $0.retryCount += 1 } + + reset() + + eventMonitor?.requestIsRetrying(self) + } + + /// Called to determine whether retry will be triggered for the particular error, or whether the instance should + /// call `finish()`. + /// + /// - Parameter error: The possible `AFError` which may trigger retry. + func retryOrFinish(error: AFError?) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + guard let error = error, let delegate = delegate else { finish(); return } + + delegate.retryResult(for: self, dueTo: error) { retryResult in + switch retryResult { + case .doNotRetry: + self.finish() + case let .doNotRetryWithError(retryError): + self.finish(error: retryError.asAFError(orFailWith: "Received retryError was not already AFError")) + case .retry, .retryWithDelay: + delegate.retryRequest(self, withDelay: retryResult.delay) + } + } + } + + /// Finishes this `Request` and starts the response serializers. + /// + /// - Parameter error: The possible `Error` with which the instance will finish. + func finish(error: AFError? = nil) { + dispatchPrecondition(condition: .onQueue(underlyingQueue)) + + guard !$mutableState.isFinishing else { return } + + $mutableState.isFinishing = true + + if let error = error { self.error = error } + + // Start response handlers + processNextResponseSerializer() + + eventMonitor?.requestDidFinish(self) + } + + /// Appends the response serialization closure to the instance. + /// + /// - Note: This method will also `resume` the instance if `delegate.startImmediately` returns `true`. + /// + /// - Parameter closure: The closure containing the response serialization call. + func appendResponseSerializer(_ closure: @escaping () -> Void) { + $mutableState.write { mutableState in + mutableState.responseSerializers.append(closure) + + if mutableState.state == .finished { + mutableState.state = .resumed + } + + if mutableState.responseSerializerProcessingFinished { + underlyingQueue.async { self.processNextResponseSerializer() } + } + + if mutableState.state.canTransitionTo(.resumed) { + underlyingQueue.async { if self.delegate?.startImmediately == true { self.resume() } } + } + } + } + + /// Returns the next response serializer closure to execute if there's one left. + /// + /// - Returns: The next response serialization closure, if there is one. + func nextResponseSerializer() -> (() -> Void)? { + var responseSerializer: (() -> Void)? + + $mutableState.write { mutableState in + let responseSerializerIndex = mutableState.responseSerializerCompletions.count + + if responseSerializerIndex < mutableState.responseSerializers.count { + responseSerializer = mutableState.responseSerializers[responseSerializerIndex] + } + } + + return responseSerializer + } + + /// Processes the next response serializer and calls all completions if response serialization is complete. + func processNextResponseSerializer() { + guard let responseSerializer = nextResponseSerializer() else { + // Execute all response serializer completions and clear them + var completions: [() -> Void] = [] + + $mutableState.write { mutableState in + completions = mutableState.responseSerializerCompletions + + // Clear out all response serializers and response serializer completions in mutable state since the + // request is complete. It's important to do this prior to calling the completion closures in case + // the completions call back into the request triggering a re-processing of the response serializers. + // An example of how this can happen is by calling cancel inside a response completion closure. + mutableState.responseSerializers.removeAll() + mutableState.responseSerializerCompletions.removeAll() + + if mutableState.state.canTransitionTo(.finished) { + mutableState.state = .finished + } + + mutableState.responseSerializerProcessingFinished = true + mutableState.isFinishing = false + } + + completions.forEach { $0() } + + // Cleanup the request + cleanup() + + return + } + + serializationQueue.async { responseSerializer() } + } + + /// Notifies the `Request` that the response serializer is complete. + /// + /// - Parameter completion: The completion handler provided with the response serializer, called when all serializers + /// are complete. + func responseSerializerDidComplete(completion: @escaping () -> Void) { + $mutableState.write { $0.responseSerializerCompletions.append(completion) } + processNextResponseSerializer() + } + + /// Resets all task and response serializer related state for retry. + func reset() { + error = nil + + uploadProgress.totalUnitCount = 0 + uploadProgress.completedUnitCount = 0 + downloadProgress.totalUnitCount = 0 + downloadProgress.completedUnitCount = 0 + + $mutableState.write { state in + state.isFinishing = false + state.responseSerializerCompletions = [] + } + } + + /// Called when updating the upload progress. + /// + /// - Parameters: + /// - totalBytesSent: Total bytes sent so far. + /// - totalBytesExpectedToSend: Total bytes expected to send. + func updateUploadProgress(totalBytesSent: Int64, totalBytesExpectedToSend: Int64) { + uploadProgress.totalUnitCount = totalBytesExpectedToSend + uploadProgress.completedUnitCount = totalBytesSent + + uploadProgressHandler?.queue.async { self.uploadProgressHandler?.handler(self.uploadProgress) } + } + + /// Perform a closure on the current `state` while locked. + /// + /// - Parameter perform: The closure to perform. + func withState(perform: (State) -> Void) { + $mutableState.withState(perform: perform) + } + + // MARK: Task Creation + + /// Called when creating a `URLSessionTask` for this `Request`. Subclasses must override. + /// + /// - Parameters: + /// - request: `URLRequest` to use to create the `URLSessionTask`. + /// - session: `URLSession` which creates the `URLSessionTask`. + /// + /// - Returns: The `URLSessionTask` created. + func task(for request: URLRequest, using session: URLSession) -> URLSessionTask { + fatalError("Subclasses must override.") + } + + // MARK: - Public API + + // These APIs are callable from any queue. + + // MARK: State + + /// Cancels the instance. Once cancelled, a `Request` can no longer be resumed or suspended. + /// + /// - Returns: The instance. + @discardableResult + public func cancel() -> Self { + $mutableState.write { mutableState in + guard mutableState.state.canTransitionTo(.cancelled) else { return } + + mutableState.state = .cancelled + + underlyingQueue.async { self.didCancel() } + + guard let task = mutableState.tasks.last, task.state != .completed else { + underlyingQueue.async { self.finish() } + return + } + + // Resume to ensure metrics are gathered. + task.resume() + task.cancel() + underlyingQueue.async { self.didCancelTask(task) } + } + + return self + } + + /// Suspends the instance. + /// + /// - Returns: The instance. + @discardableResult + public func suspend() -> Self { + $mutableState.write { mutableState in + guard mutableState.state.canTransitionTo(.suspended) else { return } + + mutableState.state = .suspended + + underlyingQueue.async { self.didSuspend() } + + guard let task = mutableState.tasks.last, task.state != .completed else { return } + + task.suspend() + underlyingQueue.async { self.didSuspendTask(task) } + } + + return self + } + + /// Resumes the instance. + /// + /// - Returns: The instance. + @discardableResult + public func resume() -> Self { + $mutableState.write { mutableState in + guard mutableState.state.canTransitionTo(.resumed) else { return } + + mutableState.state = .resumed + + underlyingQueue.async { self.didResume() } + + guard let task = mutableState.tasks.last, task.state != .completed else { return } + + task.resume() + underlyingQueue.async { self.didResumeTask(task) } + } + + return self + } + + // MARK: - Closure API + + /// Associates a credential using the provided values with the instance. + /// + /// - Parameters: + /// - username: The username. + /// - password: The password. + /// - persistence: The `URLCredential.Persistence` for the created `URLCredential`. `.forSession` by default. + /// + /// - Returns: The instance. + @discardableResult + public func authenticate(username: String, password: String, persistence: URLCredential.Persistence = .forSession) -> Self { + let credential = URLCredential(user: username, password: password, persistence: persistence) + + return authenticate(with: credential) + } + + /// Associates the provided credential with the instance. + /// + /// - Parameter credential: The `URLCredential`. + /// + /// - Returns: The instance. + @discardableResult + public func authenticate(with credential: URLCredential) -> Self { + $mutableState.credential = credential + + return self + } + + /// Sets a closure to be called periodically during the lifecycle of the instance as data is read from the server. + /// + /// - Note: Only the last closure provided is used. + /// + /// - Parameters: + /// - queue: The `DispatchQueue` to execute the closure on. `.main` by default. + /// - closure: The closure to be executed periodically as data is read from the server. + /// + /// - Returns: The instance. + @discardableResult + public func downloadProgress(queue: DispatchQueue = .main, closure: @escaping ProgressHandler) -> Self { + $mutableState.downloadProgressHandler = (handler: closure, queue: queue) + + return self + } + + /// Sets a closure to be called periodically during the lifecycle of the instance as data is sent to the server. + /// + /// - Note: Only the last closure provided is used. + /// + /// - Parameters: + /// - queue: The `DispatchQueue` to execute the closure on. `.main` by default. + /// - closure: The closure to be executed periodically as data is sent to the server. + /// + /// - Returns: The instance. + @discardableResult + public func uploadProgress(queue: DispatchQueue = .main, closure: @escaping ProgressHandler) -> Self { + $mutableState.uploadProgressHandler = (handler: closure, queue: queue) + + return self + } + + // MARK: Redirects + + /// Sets the redirect handler for the instance which will be used if a redirect response is encountered. + /// + /// - Note: Attempting to set the redirect handler more than once is a logic error and will crash. + /// + /// - Parameter handler: The `RedirectHandler`. + /// + /// - Returns: The instance. + @discardableResult + public func redirect(using handler: RedirectHandler) -> Self { + $mutableState.write { mutableState in + precondition(mutableState.redirectHandler == nil, "Redirect handler has already been set.") + mutableState.redirectHandler = handler + } + + return self + } + + // MARK: Cached Responses + + /// Sets the cached response handler for the `Request` which will be used when attempting to cache a response. + /// + /// - Note: Attempting to set the cache handler more than once is a logic error and will crash. + /// + /// - Parameter handler: The `CachedResponseHandler`. + /// + /// - Returns: The instance. + @discardableResult + public func cacheResponse(using handler: CachedResponseHandler) -> Self { + $mutableState.write { mutableState in + precondition(mutableState.cachedResponseHandler == nil, "Cached response handler has already been set.") + mutableState.cachedResponseHandler = handler + } + + return self + } + + // MARK: - Lifetime APIs + + /// Sets a handler to be called when the cURL description of the request is available. + /// + /// - Note: When waiting for a `Request`'s `URLRequest` to be created, only the last `handler` will be called. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which `handler` will be called. + /// - handler: Closure to be called when the cURL description is available. + /// + /// - Returns: The instance. + @discardableResult + public func cURLDescription(on queue: DispatchQueue, calling handler: @escaping (String) -> Void) -> Self { + $mutableState.write { mutableState in + if mutableState.requests.last != nil { + queue.async { handler(self.cURLDescription()) } + } else { + mutableState.cURLHandler = (queue, handler) + } + } + + return self + } + + /// Sets a handler to be called when the cURL description of the request is available. + /// + /// - Note: When waiting for a `Request`'s `URLRequest` to be created, only the last `handler` will be called. + /// + /// - Parameter handler: Closure to be called when the cURL description is available. Called on the instance's + /// `underlyingQueue` by default. + /// + /// - Returns: The instance. + @discardableResult + public func cURLDescription(calling handler: @escaping (String) -> Void) -> Self { + $mutableState.write { mutableState in + if mutableState.requests.last != nil { + underlyingQueue.async { handler(self.cURLDescription()) } + } else { + mutableState.cURLHandler = (underlyingQueue, handler) + } + } + + return self + } + + /// Sets a closure to called whenever Alamofire creates a `URLRequest` for this instance. + /// + /// - Note: This closure will be called multiple times if the instance adapts incoming `URLRequest`s or is retried. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which `handler` will be called. `.main` by default. + /// - handler: Closure to be called when a `URLRequest` is available. + /// + /// - Returns: The instance. + @discardableResult + public func onURLRequestCreation(on queue: DispatchQueue = .main, perform handler: @escaping (URLRequest) -> Void) -> Self { + $mutableState.write { state in + if let request = state.requests.last { + queue.async { handler(request) } + } + + state.urlRequestHandler = (queue, handler) + } + + return self + } + + /// Sets a closure to be called whenever the instance creates a `URLSessionTask`. + /// + /// - Note: This API should only be used to provide `URLSessionTask`s to existing API, like `NSFileProvider`. It + /// **SHOULD NOT** be used to interact with tasks directly, as that may be break Alamofire features. + /// Additionally, this closure may be called multiple times if the instance is retried. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which `handler` will be called. `.main` by default. + /// - handler: Closure to be called when the `URLSessionTask` is available. + /// + /// - Returns: The instance. + @discardableResult + public func onURLSessionTaskCreation(on queue: DispatchQueue = .main, perform handler: @escaping (URLSessionTask) -> Void) -> Self { + $mutableState.write { state in + if let task = state.tasks.last { + queue.async { handler(task) } + } + + state.urlSessionTaskHandler = (queue, handler) + } + + return self + } + + // MARK: Cleanup + + /// Adds a `finishHandler` closure to be called when the request completes. + /// + /// - Parameter closure: Closure to be called when the request finishes. + func onFinish(perform finishHandler: @escaping () -> Void) { + guard !isFinished else { finishHandler(); return } + + $mutableState.write { state in + state.finishHandlers.append(finishHandler) + } + } + + /// Final cleanup step executed when the instance finishes response serialization. + func cleanup() { + delegate?.cleanup(after: self) + let handlers = $mutableState.finishHandlers + handlers.forEach { $0() } + $mutableState.write { state in + state.finishHandlers.removeAll() + } + } +} + +// MARK: - Protocol Conformances + +extension Request: Equatable { + public static func ==(lhs: Request, rhs: Request) -> Bool { + lhs.id == rhs.id + } +} + +extension Request: Hashable { + public func hash(into hasher: inout Hasher) { + hasher.combine(id) + } +} + +extension Request: CustomStringConvertible { + /// A textual representation of this instance, including the `HTTPMethod` and `URL` if the `URLRequest` has been + /// created, as well as the response status code, if a response has been received. + public var description: String { + guard let request = performedRequests.last ?? lastRequest, + let url = request.url, + let method = request.httpMethod else { return "No request created yet." } + + let requestDescription = "\(method) \(url.absoluteString)" + + return response.map { "\(requestDescription) (\($0.statusCode))" } ?? requestDescription + } +} + +extension Request { + /// cURL representation of the instance. + /// + /// - Returns: The cURL equivalent of the instance. + public func cURLDescription() -> String { + guard + let request = lastRequest, + let url = request.url, + let host = url.host, + let method = request.httpMethod else { return "$ curl command could not be created" } + + var components = ["$ curl -v"] + + components.append("-X \(method)") + + if let credentialStorage = delegate?.sessionConfiguration.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 = credential, let user = credential.user, let password = credential.password { + components.append("-u \(user):\(password)") + } + } + } + + if let configuration = delegate?.sessionConfiguration, configuration.httpShouldSetCookies { + if + let cookieStorage = configuration.httpCookieStorage, + let cookies = cookieStorage.cookies(for: url), !cookies.isEmpty { + let allCookies = cookies.map { "\($0.name)=\($0.value)" }.joined(separator: ";") + + components.append("-b \"\(allCookies)\"") + } + } + + var headers = HTTPHeaders() + + if let sessionHeaders = delegate?.sessionConfiguration.headers { + for header in sessionHeaders where header.name != "Cookie" { + headers[header.name] = header.value + } + } + + for header in request.headers where header.name != "Cookie" { + headers[header.name] = header.value + } + + for header in headers { + let escapedValue = header.value.replacingOccurrences(of: "\"", with: "\\\"") + components.append("-H \"\(header.name): \(escapedValue)\"") + } + + if let httpBodyData = request.httpBody { + let httpBody = String(decoding: httpBodyData, as: UTF8.self) + var escapedBody = httpBody.replacingOccurrences(of: "\\\"", with: "\\\\\"") + escapedBody = escapedBody.replacingOccurrences(of: "\"", with: "\\\"") + + components.append("-d \"\(escapedBody)\"") + } + + components.append("\"\(url.absoluteString)\"") + + return components.joined(separator: " \\\n\t") + } +} + +/// Protocol abstraction for `Request`'s communication back to the `SessionDelegate`. +public protocol RequestDelegate: AnyObject { + /// `URLSessionConfiguration` used to create the underlying `URLSessionTask`s. + var sessionConfiguration: URLSessionConfiguration { get } + + /// Determines whether the `Request` should automatically call `resume()` when adding the first response handler. + var startImmediately: Bool { get } + + /// Notifies the delegate the `Request` has reached a point where it needs cleanup. + /// + /// - Parameter request: The `Request` to cleanup after. + func cleanup(after request: Request) + + /// Asynchronously ask the delegate whether a `Request` will be retried. + /// + /// - Parameters: + /// - request: `Request` which failed. + /// - error: `Error` which produced the failure. + /// - completion: Closure taking the `RetryResult` for evaluation. + func retryResult(for request: Request, dueTo error: AFError, completion: @escaping (RetryResult) -> Void) + + /// Asynchronously retry the `Request`. + /// + /// - Parameters: + /// - request: `Request` which will be retried. + /// - timeDelay: `TimeInterval` after which the retry will be triggered. + func retryRequest(_ request: Request, withDelay timeDelay: TimeInterval?) +} + +// MARK: - Subclasses + +// MARK: - DataRequest + +/// `Request` subclass which handles in-memory `Data` download using `URLSessionDataTask`. +public class DataRequest: Request { + /// `URLRequestConvertible` value used to create `URLRequest`s for this instance. + public let convertible: URLRequestConvertible + /// `Data` read from the server so far. + public var data: Data? { mutableData } + + /// Protected storage for the `Data` read by the instance. + @Protected + private var mutableData: Data? = nil + + /// Creates a `DataRequest` using the provided parameters. + /// + /// - Parameters: + /// - id: `UUID` used for the `Hashable` and `Equatable` implementations. `UUID()` by default. + /// - convertible: `URLRequestConvertible` value used to create `URLRequest`s for this instance. + /// - underlyingQueue: `DispatchQueue` on which all internal `Request` work is performed. + /// - serializationQueue: `DispatchQueue` on which all serialization work is performed. By default targets + /// `underlyingQueue`, but can be passed another queue from a `Session`. + /// - eventMonitor: `EventMonitor` called for event callbacks from internal `Request` actions. + /// - interceptor: `RequestInterceptor` used throughout the request lifecycle. + /// - delegate: `RequestDelegate` that provides an interface to actions not performed by the `Request`. + init(id: UUID = UUID(), + convertible: URLRequestConvertible, + underlyingQueue: DispatchQueue, + serializationQueue: DispatchQueue, + eventMonitor: EventMonitor?, + interceptor: RequestInterceptor?, + delegate: RequestDelegate) { + self.convertible = convertible + + super.init(id: id, + underlyingQueue: underlyingQueue, + serializationQueue: serializationQueue, + eventMonitor: eventMonitor, + interceptor: interceptor, + delegate: delegate) + } + + override func reset() { + super.reset() + + mutableData = nil + } + + /// Called when `Data` is received by this instance. + /// + /// - Note: Also calls `updateDownloadProgress`. + /// + /// - Parameter data: The `Data` received. + func didReceive(data: Data) { + if self.data == nil { + mutableData = data + } else { + $mutableData.write { $0?.append(data) } + } + + updateDownloadProgress() + } + + override func task(for request: URLRequest, using session: URLSession) -> URLSessionTask { + let copiedRequest = request + return session.dataTask(with: copiedRequest) + } + + /// Called to updated the `downloadProgress` of the instance. + func updateDownloadProgress() { + let totalBytesReceived = Int64(data?.count ?? 0) + let totalBytesExpected = task?.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown + + downloadProgress.totalUnitCount = totalBytesExpected + downloadProgress.completedUnitCount = totalBytesReceived + + downloadProgressHandler?.queue.async { self.downloadProgressHandler?.handler(self.downloadProgress) } + } + + /// Validates the request, using the specified closure. + /// + /// - Note: If validation fails, subsequent calls to response handlers will have an associated error. + /// + /// - Parameter validation: `Validation` closure used to validate the response. + /// + /// - Returns: The instance. + @discardableResult + public func validate(_ validation: @escaping Validation) -> Self { + let validator: () -> Void = { [unowned self] in + guard self.error == nil, let response = self.response else { return } + + let result = validation(self.request, response, self.data) + + if case let .failure(error) = result { self.error = error.asAFError(or: .responseValidationFailed(reason: .customValidationFailed(error: error))) } + + self.eventMonitor?.request(self, + didValidateRequest: self.request, + response: response, + data: self.data, + withResult: result) + } + + $validators.write { $0.append(validator) } + + return self + } +} + +// MARK: - DataStreamRequest + +/// `Request` subclass which streams HTTP response `Data` through a `Handler` closure. +public final class DataStreamRequest: Request { + /// Closure type handling `DataStreamRequest.Stream` values. + public typealias Handler = (Stream) throws -> Void + + /// Type encapsulating an `Event` as it flows through the stream, as well as a `CancellationToken` which can be used + /// to stop the stream at any time. + public struct Stream { + /// Latest `Event` from the stream. + public let event: Event + /// Token used to cancel the stream. + public let token: CancellationToken + + /// Cancel the ongoing stream by canceling the underlying `DataStreamRequest`. + public func cancel() { + token.cancel() + } + } + + /// Type representing an event flowing through the stream. Contains either the `Result` of processing streamed + /// `Data` or the completion of the stream. + public enum Event { + /// Output produced every time the instance receives additional `Data`. The associated value contains the + /// `Result` of processing the incoming `Data`. + case stream(Result) + /// Output produced when the instance has completed, whether due to stream end, cancellation, or an error. + /// Associated `Completion` value contains the final state. + case complete(Completion) + } + + /// Value containing the state of a `DataStreamRequest` when the stream was completed. + public struct Completion { + /// Last `URLRequest` issued by the instance. + public let request: URLRequest? + /// Last `HTTPURLResponse` received by the instance. + public let response: HTTPURLResponse? + /// Last `URLSessionTaskMetrics` produced for the instance. + public let metrics: URLSessionTaskMetrics? + /// `AFError` produced for the instance, if any. + public let error: AFError? + } + + /// Type used to cancel an ongoing stream. + public struct CancellationToken { + weak var request: DataStreamRequest? + + init(_ request: DataStreamRequest) { + self.request = request + } + + /// Cancel the ongoing stream by canceling the underlying `DataStreamRequest`. + public func cancel() { + request?.cancel() + } + } + + /// `URLRequestConvertible` value used to create `URLRequest`s for this instance. + public let convertible: URLRequestConvertible + /// Whether or not the instance will be cancelled if stream parsing encounters an error. + public let automaticallyCancelOnStreamError: Bool + + /// Internal mutable state specific to this type. + struct StreamMutableState { + /// `OutputStream` bound to the `InputStream` produced by `asInputStream`, if it has been called. + var outputStream: OutputStream? + /// Stream closures called as `Data` is received. + var streams: [(_ data: Data) -> Void] = [] + /// Number of currently executing streams. Used to ensure completions are only fired after all streams are + /// enqueued. + var numberOfExecutingStreams = 0 + /// Completion calls enqueued while streams are still executing. + var enqueuedCompletionEvents: [() -> Void] = [] + } + + @Protected + var streamMutableState = StreamMutableState() + + /// Creates a `DataStreamRequest` using the provided parameters. + /// + /// - Parameters: + /// - id: `UUID` used for the `Hashable` and `Equatable` implementations. `UUID()` + /// by default. + /// - convertible: `URLRequestConvertible` value used to create `URLRequest`s for this + /// instance. + /// - automaticallyCancelOnStreamError: `Bool` indicating whether the instance will be cancelled when an `Error` + /// is thrown while serializing stream `Data`. + /// - underlyingQueue: `DispatchQueue` on which all internal `Request` work is performed. + /// - serializationQueue: `DispatchQueue` on which all serialization work is performed. By default + /// targets + /// `underlyingQueue`, but can be passed another queue from a `Session`. + /// - eventMonitor: `EventMonitor` called for event callbacks from internal `Request` actions. + /// - interceptor: `RequestInterceptor` used throughout the request lifecycle. + /// - delegate: `RequestDelegate` that provides an interface to actions not performed by + /// the `Request`. + init(id: UUID = UUID(), + convertible: URLRequestConvertible, + automaticallyCancelOnStreamError: Bool, + underlyingQueue: DispatchQueue, + serializationQueue: DispatchQueue, + eventMonitor: EventMonitor?, + interceptor: RequestInterceptor?, + delegate: RequestDelegate) { + self.convertible = convertible + self.automaticallyCancelOnStreamError = automaticallyCancelOnStreamError + + super.init(id: id, + underlyingQueue: underlyingQueue, + serializationQueue: serializationQueue, + eventMonitor: eventMonitor, + interceptor: interceptor, + delegate: delegate) + } + + override func task(for request: URLRequest, using session: URLSession) -> URLSessionTask { + let copiedRequest = request + return session.dataTask(with: copiedRequest) + } + + override func finish(error: AFError? = nil) { + $streamMutableState.write { state in + state.outputStream?.close() + } + + super.finish(error: error) + } + + func didReceive(data: Data) { + $streamMutableState.write { state in + #if !(os(Linux) || os(Windows)) + if let stream = state.outputStream { + underlyingQueue.async { + var bytes = Array(data) + stream.write(&bytes, maxLength: bytes.count) + } + } + #endif + state.numberOfExecutingStreams += state.streams.count + let localState = state + underlyingQueue.async { localState.streams.forEach { $0(data) } } + } + } + + /// Validates the `URLRequest` and `HTTPURLResponse` received for the instance using the provided `Validation` closure. + /// + /// - Parameter validation: `Validation` closure used to validate the request and response. + /// + /// - Returns: The `DataStreamRequest`. + @discardableResult + public func validate(_ validation: @escaping Validation) -> Self { + let validator: () -> Void = { [unowned self] in + guard self.error == nil, let response = self.response else { return } + + let result = validation(self.request, response) + + if case let .failure(error) = result { + self.error = error.asAFError(or: .responseValidationFailed(reason: .customValidationFailed(error: error))) + } + + self.eventMonitor?.request(self, + didValidateRequest: self.request, + response: response, + withResult: result) + } + + $validators.write { $0.append(validator) } + + return self + } + + #if !(os(Linux) || os(Windows)) + /// Produces an `InputStream` that receives the `Data` received by the instance. + /// + /// - Note: The `InputStream` produced by this method must have `open()` called before being able to read `Data`. + /// Additionally, this method will automatically call `resume()` on the instance, regardless of whether or + /// not the creating session has `startRequestsImmediately` set to `true`. + /// + /// - Parameter bufferSize: Size, in bytes, of the buffer between the `OutputStream` and `InputStream`. + /// + /// - Returns: The `InputStream` bound to the internal `OutboundStream`. + public func asInputStream(bufferSize: Int = 1024) -> InputStream? { + defer { resume() } + + var inputStream: InputStream? + $streamMutableState.write { state in + Foundation.Stream.getBoundStreams(withBufferSize: bufferSize, + inputStream: &inputStream, + outputStream: &state.outputStream) + state.outputStream?.open() + } + + return inputStream + } + #endif + + func capturingError(from closure: () throws -> Void) { + do { + try closure() + } catch { + self.error = error.asAFError(or: .responseSerializationFailed(reason: .customSerializationFailed(error: error))) + cancel() + } + } + + func appendStreamCompletion(on queue: DispatchQueue, + stream: @escaping Handler) { + appendResponseSerializer { + self.underlyingQueue.async { + self.responseSerializerDidComplete { + self.$streamMutableState.write { state in + guard state.numberOfExecutingStreams == 0 else { + state.enqueuedCompletionEvents.append { + self.enqueueCompletion(on: queue, stream: stream) + } + + return + } + + self.enqueueCompletion(on: queue, stream: stream) + } + } + } + } + } + + func enqueueCompletion(on queue: DispatchQueue, + stream: @escaping Handler) { + queue.async { + do { + let completion = Completion(request: self.request, + response: self.response, + metrics: self.metrics, + error: self.error) + try stream(.init(event: .complete(completion), token: .init(self))) + } catch { + // Ignore error, as errors on Completion can't be handled anyway. + } + } + } +} + +extension DataStreamRequest.Stream { + /// Incoming `Result` values from `Event.stream`. + public var result: Result? { + guard case let .stream(result) = event else { return nil } + + return result + } + + /// `Success` value of the instance, if any. + public var value: Success? { + guard case let .success(value) = result else { return nil } + + return value + } + + /// `Failure` value of the instance, if any. + public var error: Failure? { + guard case let .failure(error) = result else { return nil } + + return error + } + + /// `Completion` value of the instance, if any. + public var completion: DataStreamRequest.Completion? { + guard case let .complete(completion) = event else { return nil } + + return completion + } +} + +// MARK: - DownloadRequest + +/// `Request` subclass which downloads `Data` to a file on disk using `URLSessionDownloadTask`. +public class DownloadRequest: Request { + /// A set of options to be executed prior to moving a downloaded file from the temporary `URL` to the destination + /// `URL`. + public struct Options: OptionSet { + /// Specifies that intermediate directories for the destination URL should be created. + public static let createIntermediateDirectories = Options(rawValue: 1 << 0) + /// Specifies that any previous file at the destination `URL` should be removed. + public static let removePreviousFile = Options(rawValue: 1 << 1) + + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + } + + // MARK: Destination + + /// A closure executed once a `DownloadRequest` 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 `HTTPURLResponse`, and returns two values: the file URL where the temporary file should be moved and + /// the options defining how the file should be moved. + /// + /// - Note: Downloads from a local `file://` `URL`s do not use the `Destination` closure, as those downloads do not + /// return an `HTTPURLResponse`. Instead the file is merely moved within the temporary directory. + public typealias Destination = (_ temporaryURL: URL, + _ response: HTTPURLResponse) -> (destinationURL: URL, options: Options) + + /// 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. + /// + /// - Parameters: + /// - directory: The search path directory. `.documentDirectory` by default. + /// - domain: The search path domain mask. `.userDomainMask` by default. + /// - options: `DownloadRequest.Options` used when moving the downloaded file to its destination. None by + /// default. + /// - Returns: The `Destination` closure. + public class func suggestedDownloadDestination(for directory: FileManager.SearchPathDirectory = .documentDirectory, + in domain: FileManager.SearchPathDomainMask = .userDomainMask, + options: Options = []) -> Destination { + { temporaryURL, response in + let directoryURLs = FileManager.default.urls(for: directory, in: domain) + let url = directoryURLs.first?.appendingPathComponent(response.suggestedFilename!) ?? temporaryURL + + return (url, options) + } + } + + /// Default `Destination` used by Alamofire to ensure all downloads persist. This `Destination` prepends + /// `Alamofire_` to the automatically generated download name and moves it within the temporary directory. Files + /// with this destination must be additionally moved if they should survive the system reclamation of temporary + /// space. + static let defaultDestination: Destination = { url, _ in + (defaultDestinationURL(url), []) + } + + /// Default `URL` creation closure. Creates a `URL` in the temporary directory with `Alamofire_` prepended to the + /// provided file name. + static let defaultDestinationURL: (URL) -> URL = { url in + let filename = "Alamofire_\(url.lastPathComponent)" + let destination = url.deletingLastPathComponent().appendingPathComponent(filename) + + return destination + } + + // MARK: Downloadable + + /// Type describing the source used to create the underlying `URLSessionDownloadTask`. + public enum Downloadable { + /// Download should be started from the `URLRequest` produced by the associated `URLRequestConvertible` value. + case request(URLRequestConvertible) + /// Download should be started from the associated resume `Data` value. + case resumeData(Data) + } + + // MARK: Mutable State + + /// Type containing all mutable state for `DownloadRequest` instances. + private struct DownloadRequestMutableState { + /// Possible resume `Data` produced when cancelling the instance. + var resumeData: Data? + /// `URL` to which `Data` is being downloaded. + var fileURL: URL? + } + + /// Protected mutable state specific to `DownloadRequest`. + @Protected + private var mutableDownloadState = DownloadRequestMutableState() + + /// If the download is resumable and is eventually cancelled or fails, this value may be used to resume the download + /// using the `download(resumingWith data:)` API. + /// + /// - Note: For more information about `resumeData`, see [Apple's documentation](https://developer.apple.com/documentation/foundation/urlsessiondownloadtask/1411634-cancel). + public var resumeData: Data? { + #if !(os(Linux) || os(Windows)) + return $mutableDownloadState.resumeData ?? error?.downloadResumeData + #else + return $mutableDownloadState.resumeData + #endif + } + + /// If the download is successful, the `URL` where the file was downloaded. + public var fileURL: URL? { $mutableDownloadState.fileURL } + + // MARK: Initial State + + /// `Downloadable` value used for this instance. + public let downloadable: Downloadable + /// The `Destination` to which the downloaded file is moved. + let destination: Destination + + /// Creates a `DownloadRequest` using the provided parameters. + /// + /// - Parameters: + /// - id: `UUID` used for the `Hashable` and `Equatable` implementations. `UUID()` by default. + /// - downloadable: `Downloadable` value used to create `URLSessionDownloadTasks` for the instance. + /// - underlyingQueue: `DispatchQueue` on which all internal `Request` work is performed. + /// - serializationQueue: `DispatchQueue` on which all serialization work is performed. By default targets + /// `underlyingQueue`, but can be passed another queue from a `Session`. + /// - eventMonitor: `EventMonitor` called for event callbacks from internal `Request` actions. + /// - interceptor: `RequestInterceptor` used throughout the request lifecycle. + /// - delegate: `RequestDelegate` that provides an interface to actions not performed by the `Request` + /// - destination: `Destination` closure used to move the downloaded file to its final location. + init(id: UUID = UUID(), + downloadable: Downloadable, + underlyingQueue: DispatchQueue, + serializationQueue: DispatchQueue, + eventMonitor: EventMonitor?, + interceptor: RequestInterceptor?, + delegate: RequestDelegate, + destination: @escaping Destination) { + self.downloadable = downloadable + self.destination = destination + + super.init(id: id, + underlyingQueue: underlyingQueue, + serializationQueue: serializationQueue, + eventMonitor: eventMonitor, + interceptor: interceptor, + delegate: delegate) + } + + override func reset() { + super.reset() + + $mutableDownloadState.write { + $0.resumeData = nil + $0.fileURL = nil + } + } + + /// Called when a download has finished. + /// + /// - Parameters: + /// - task: `URLSessionTask` that finished the download. + /// - result: `Result` of the automatic move to `destination`. + func didFinishDownloading(using task: URLSessionTask, with result: Result) { + eventMonitor?.request(self, didFinishDownloadingUsing: task, with: result) + + switch result { + case let .success(url): $mutableDownloadState.fileURL = url + case let .failure(error): self.error = error + } + } + + /// Updates the `downloadProgress` using the provided values. + /// + /// - Parameters: + /// - bytesWritten: Total bytes written so far. + /// - totalBytesExpectedToWrite: Total bytes expected to write. + func updateDownloadProgress(bytesWritten: Int64, totalBytesExpectedToWrite: Int64) { + downloadProgress.totalUnitCount = totalBytesExpectedToWrite + downloadProgress.completedUnitCount += bytesWritten + + downloadProgressHandler?.queue.async { self.downloadProgressHandler?.handler(self.downloadProgress) } + } + + override func task(for request: URLRequest, using session: URLSession) -> URLSessionTask { + session.downloadTask(with: request) + } + + /// Creates a `URLSessionTask` from the provided resume data. + /// + /// - Parameters: + /// - data: `Data` used to resume the download. + /// - session: `URLSession` used to create the `URLSessionTask`. + /// + /// - Returns: The `URLSessionTask` created. + public func task(forResumeData data: Data, using session: URLSession) -> URLSessionTask { + session.downloadTask(withResumeData: data) + } + + /// Cancels the instance. Once cancelled, a `DownloadRequest` can no longer be resumed or suspended. + /// + /// - Note: This method will NOT produce resume data. If you wish to cancel and produce resume data, use + /// `cancel(producingResumeData:)` or `cancel(byProducingResumeData:)`. + /// + /// - Returns: The instance. + @discardableResult + override public func cancel() -> Self { + cancel(producingResumeData: false) + } + + /// Cancels the instance, optionally producing resume data. Once cancelled, a `DownloadRequest` can no longer be + /// resumed or suspended. + /// + /// - Note: If `producingResumeData` is `true`, the `resumeData` property will be populated with any resume data, if + /// available. + /// + /// - Returns: The instance. + @discardableResult + public func cancel(producingResumeData shouldProduceResumeData: Bool) -> Self { + cancel(optionallyProducingResumeData: shouldProduceResumeData ? { _ in } : nil) + } + + /// Cancels the instance while producing resume data. Once cancelled, a `DownloadRequest` can no longer be resumed + /// or suspended. + /// + /// - Note: The resume data passed to the completion handler will also be available on the instance's `resumeData` + /// property. + /// + /// - Parameter completionHandler: The completion handler that is called when the download has been successfully + /// cancelled. It is not guaranteed to be called on a particular queue, so you may + /// want use an appropriate queue to perform your work. + /// + /// - Returns: The instance. + @discardableResult + public func cancel(byProducingResumeData completionHandler: @escaping (_ data: Data?) -> Void) -> Self { + cancel(optionallyProducingResumeData: completionHandler) + } + + /// Internal implementation of cancellation that optionally takes a resume data handler. If no handler is passed, + /// cancellation is performed without producing resume data. + /// + /// - Parameter completionHandler: Optional resume data handler. + /// + /// - Returns: The instance. + private func cancel(optionallyProducingResumeData completionHandler: ((_ resumeData: Data?) -> Void)?) -> Self { + $mutableState.write { mutableState in + guard mutableState.state.canTransitionTo(.cancelled) else { return } + + mutableState.state = .cancelled + + underlyingQueue.async { self.didCancel() } + + guard let task = mutableState.tasks.last as? URLSessionDownloadTask, task.state != .completed else { + underlyingQueue.async { self.finish() } + return + } + + if let completionHandler = completionHandler { + // Resume to ensure metrics are gathered. + task.resume() + task.cancel { resumeData in + self.$mutableDownloadState.resumeData = resumeData + self.underlyingQueue.async { self.didCancelTask(task) } + completionHandler(resumeData) + } + } else { + // Resume to ensure metrics are gathered. + task.resume() + task.cancel(byProducingResumeData: { _ in }) + self.underlyingQueue.async { self.didCancelTask(task) } + } + } + + return self + } + + /// Validates the request, using the specified closure. + /// + /// - Note: If validation fails, subsequent calls to response handlers will have an associated error. + /// + /// - Parameter validation: `Validation` closure to validate the response. + /// + /// - Returns: The instance. + @discardableResult + public func validate(_ validation: @escaping Validation) -> Self { + let validator: () -> Void = { [unowned self] in + guard self.error == nil, let response = self.response else { return } + + let result = validation(self.request, response, self.fileURL) + + if case let .failure(error) = result { + self.error = error.asAFError(or: .responseValidationFailed(reason: .customValidationFailed(error: error))) + } + + self.eventMonitor?.request(self, + didValidateRequest: self.request, + response: response, + fileURL: self.fileURL, + withResult: result) + } + + $validators.write { $0.append(validator) } + + return self + } +} + +// MARK: - UploadRequest + +/// `DataRequest` subclass which handles `Data` upload from memory, file, or stream using `URLSessionUploadTask`. +public class UploadRequest: DataRequest { + /// Type describing the origin of the upload, whether `Data`, file, or stream. + public enum Uploadable { + /// Upload from the provided `Data` value. + case data(Data) + /// Upload from the provided file `URL`, as well as a `Bool` determining whether the source file should be + /// automatically removed once uploaded. + case file(URL, shouldRemove: Bool) + /// Upload from the provided `InputStream`. + case stream(InputStream) + } + + // MARK: Initial State + + /// The `UploadableConvertible` value used to produce the `Uploadable` value for this instance. + public let upload: UploadableConvertible + + /// `FileManager` used to perform cleanup tasks, including the removal of multipart form encoded payloads written + /// to disk. + public let fileManager: FileManager + + // MARK: Mutable State + + /// `Uploadable` value used by the instance. + public var uploadable: Uploadable? + + /// Creates an `UploadRequest` using the provided parameters. + /// + /// - Parameters: + /// - id: `UUID` used for the `Hashable` and `Equatable` implementations. `UUID()` by default. + /// - convertible: `UploadConvertible` value used to determine the type of upload to be performed. + /// - underlyingQueue: `DispatchQueue` on which all internal `Request` work is performed. + /// - serializationQueue: `DispatchQueue` on which all serialization work is performed. By default targets + /// `underlyingQueue`, but can be passed another queue from a `Session`. + /// - eventMonitor: `EventMonitor` called for event callbacks from internal `Request` actions. + /// - interceptor: `RequestInterceptor` used throughout the request lifecycle. + /// - fileManager: `FileManager` used to perform cleanup tasks, including the removal of multipart form + /// encoded payloads written to disk. + /// - delegate: `RequestDelegate` that provides an interface to actions not performed by the `Request`. + init(id: UUID = UUID(), + convertible: UploadConvertible, + underlyingQueue: DispatchQueue, + serializationQueue: DispatchQueue, + eventMonitor: EventMonitor?, + interceptor: RequestInterceptor?, + fileManager: FileManager, + delegate: RequestDelegate) { + upload = convertible + self.fileManager = fileManager + + super.init(id: id, + convertible: convertible, + underlyingQueue: underlyingQueue, + serializationQueue: serializationQueue, + eventMonitor: eventMonitor, + interceptor: interceptor, + delegate: delegate) + } + + /// Called when the `Uploadable` value has been created from the `UploadConvertible`. + /// + /// - Parameter uploadable: The `Uploadable` that was created. + func didCreateUploadable(_ uploadable: Uploadable) { + self.uploadable = uploadable + + eventMonitor?.request(self, didCreateUploadable: uploadable) + } + + /// Called when the `Uploadable` value could not be created. + /// + /// - Parameter error: `AFError` produced by the failure. + func didFailToCreateUploadable(with error: AFError) { + self.error = error + + eventMonitor?.request(self, didFailToCreateUploadableWithError: error) + + retryOrFinish(error: error) + } + + override func task(for request: URLRequest, using session: URLSession) -> URLSessionTask { + guard let uploadable = uploadable else { + fatalError("Attempting to create a URLSessionUploadTask when Uploadable value doesn't exist.") + } + + switch uploadable { + case let .data(data): return session.uploadTask(with: request, from: data) + case let .file(url, _): return session.uploadTask(with: request, fromFile: url) + case .stream: return session.uploadTask(withStreamedRequest: request) + } + } + + override func reset() { + // Uploadable must be recreated on every retry. + uploadable = nil + + super.reset() + } + + /// Produces the `InputStream` from `uploadable`, if it can. + /// + /// - Note: Calling this method with a non-`.stream` `Uploadable` is a logic error and will crash. + /// + /// - Returns: The `InputStream`. + func inputStream() -> InputStream { + guard let uploadable = uploadable else { + fatalError("Attempting to access the input stream but the uploadable doesn't exist.") + } + + guard case let .stream(stream) = uploadable else { + fatalError("Attempted to access the stream of an UploadRequest that wasn't created with one.") + } + + eventMonitor?.request(self, didProvideInputStream: stream) + + return stream + } + + override public func cleanup() { + defer { super.cleanup() } + + guard + let uploadable = uploadable, + case let .file(url, shouldRemove) = uploadable, + shouldRemove + else { return } + + try? fileManager.removeItem(at: url) + } +} + +/// A type that can produce an `UploadRequest.Uploadable` value. +public protocol UploadableConvertible { + /// Produces an `UploadRequest.Uploadable` value from the instance. + /// + /// - Returns: The `UploadRequest.Uploadable`. + /// - Throws: Any `Error` produced during creation. + func createUploadable() throws -> UploadRequest.Uploadable +} + +extension UploadRequest.Uploadable: UploadableConvertible { + public func createUploadable() throws -> UploadRequest.Uploadable { + self + } +} + +/// A type that can be converted to an upload, whether from an `UploadRequest.Uploadable` or `URLRequestConvertible`. +public protocol UploadConvertible: UploadableConvertible & URLRequestConvertible {} diff --git a/Instagram-Clone/Pods/Alamofire/Source/RequestInterceptor.swift b/Instagram-Clone/Pods/Alamofire/Source/RequestInterceptor.swift new file mode 100644 index 0000000..7ed39a5 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/RequestInterceptor.swift @@ -0,0 +1,357 @@ +// +// RequestInterceptor.swift +// +// Copyright (c) 2019 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 + +/// Stores all state associated with a `URLRequest` being adapted. +public struct RequestAdapterState { + /// The `UUID` of the `Request` associated with the `URLRequest` to adapt. + public let requestID: UUID + + /// The `Session` associated with the `URLRequest` to adapt. + public let session: Session +} + +// MARK: - + +/// 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 and calls the completion handler with the Result. + /// + /// - Parameters: + /// - urlRequest: The `URLRequest` to adapt. + /// - session: The `Session` that will execute the `URLRequest`. + /// - completion: The completion handler that must be called when adaptation is complete. + func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) + + /// Inspects and adapts the specified `URLRequest` in some manner and calls the completion handler with the Result. + /// + /// - Parameters: + /// - urlRequest: The `URLRequest` to adapt. + /// - state: The `RequestAdapterState` associated with the `URLRequest`. + /// - completion: The completion handler that must be called when adaptation is complete. + func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping (Result) -> Void) +} + +extension RequestAdapter { + public func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping (Result) -> Void) { + adapt(urlRequest, for: state.session, completion: completion) + } +} + +// MARK: - + +/// Outcome of determination whether retry is necessary. +public enum RetryResult { + /// Retry should be attempted immediately. + case retry + /// Retry should be attempted after the associated `TimeInterval`. + case retryWithDelay(TimeInterval) + /// Do not retry. + case doNotRetry + /// Do not retry due to the associated `Error`. + case doNotRetryWithError(Error) +} + +extension RetryResult { + var retryRequired: Bool { + switch self { + case .retry, .retryWithDelay: return true + default: return false + } + } + + var delay: TimeInterval? { + switch self { + case let .retryWithDelay(delay): return delay + default: return nil + } + } + + var error: Error? { + guard case let .doNotRetryWithError(error) = self else { return nil } + return error + } +} + +/// 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. + /// + /// - Parameters: + /// - request: `Request` that failed due to the provided `Error`. + /// - session: `Session` that produced the `Request`. + /// - error: `Error` encountered while executing the `Request`. + /// - completion: Completion closure to be executed when a retry decision has been determined. + func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) +} + +// MARK: - + +/// Type that provides both `RequestAdapter` and `RequestRetrier` functionality. +public protocol RequestInterceptor: RequestAdapter, RequestRetrier {} + +extension RequestInterceptor { + public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { + completion(.success(urlRequest)) + } + + public func retry(_ request: Request, + for session: Session, + dueTo error: Error, + completion: @escaping (RetryResult) -> Void) { + completion(.doNotRetry) + } +} + +/// `RequestAdapter` closure definition. +public typealias AdaptHandler = (URLRequest, Session, _ completion: @escaping (Result) -> Void) -> Void +/// `RequestRetrier` closure definition. +public typealias RetryHandler = (Request, Session, Error, _ completion: @escaping (RetryResult) -> Void) -> Void + +// MARK: - + +/// Closure-based `RequestAdapter`. +open class Adapter: RequestInterceptor { + private let adaptHandler: AdaptHandler + + /// Creates an instance using the provided closure. + /// + /// - Parameter adaptHandler: `AdaptHandler` closure to be executed when handling request adaptation. + public init(_ adaptHandler: @escaping AdaptHandler) { + self.adaptHandler = adaptHandler + } + + open func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { + adaptHandler(urlRequest, session, completion) + } + + open func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping (Result) -> Void) { + adaptHandler(urlRequest, state.session, completion) + } +} + +#if swift(>=5.5) +extension RequestAdapter where Self == Adapter { + /// Creates an `Adapter` using the provided `AdaptHandler` closure. + /// + /// - Parameter closure: `AdaptHandler` to use to adapt the request. + /// - Returns: The `Adapter`. + public static func adapter(using closure: @escaping AdaptHandler) -> Adapter { + Adapter(closure) + } +} +#endif + +// MARK: - + +/// Closure-based `RequestRetrier`. +open class Retrier: RequestInterceptor { + private let retryHandler: RetryHandler + + /// Creates an instance using the provided closure. + /// + /// - Parameter retryHandler: `RetryHandler` closure to be executed when handling request retry. + public init(_ retryHandler: @escaping RetryHandler) { + self.retryHandler = retryHandler + } + + open func retry(_ request: Request, + for session: Session, + dueTo error: Error, + completion: @escaping (RetryResult) -> Void) { + retryHandler(request, session, error, completion) + } +} + +#if swift(>=5.5) +extension RequestRetrier where Self == Retrier { + /// Creates a `Retrier` using the provided `RetryHandler` closure. + /// + /// - Parameter closure: `RetryHandler` to use to retry the request. + /// - Returns: The `Retrier`. + public static func retrier(using closure: @escaping RetryHandler) -> Retrier { + Retrier(closure) + } +} +#endif + +// MARK: - + +/// `RequestInterceptor` which can use multiple `RequestAdapter` and `RequestRetrier` values. +open class Interceptor: RequestInterceptor { + /// All `RequestAdapter`s associated with the instance. These adapters will be run until one fails. + public let adapters: [RequestAdapter] + /// All `RequestRetrier`s associated with the instance. These retriers will be run one at a time until one triggers retry. + public let retriers: [RequestRetrier] + + /// Creates an instance from `AdaptHandler` and `RetryHandler` closures. + /// + /// - Parameters: + /// - adaptHandler: `AdaptHandler` closure to be used. + /// - retryHandler: `RetryHandler` closure to be used. + public init(adaptHandler: @escaping AdaptHandler, retryHandler: @escaping RetryHandler) { + adapters = [Adapter(adaptHandler)] + retriers = [Retrier(retryHandler)] + } + + /// Creates an instance from `RequestAdapter` and `RequestRetrier` values. + /// + /// - Parameters: + /// - adapter: `RequestAdapter` value to be used. + /// - retrier: `RequestRetrier` value to be used. + public init(adapter: RequestAdapter, retrier: RequestRetrier) { + adapters = [adapter] + retriers = [retrier] + } + + /// Creates an instance from the arrays of `RequestAdapter` and `RequestRetrier` values. + /// + /// - Parameters: + /// - adapters: `RequestAdapter` values to be used. + /// - retriers: `RequestRetrier` values to be used. + /// - interceptors: `RequestInterceptor`s to be used. + public init(adapters: [RequestAdapter] = [], retriers: [RequestRetrier] = [], interceptors: [RequestInterceptor] = []) { + self.adapters = adapters + interceptors + self.retriers = retriers + interceptors + } + + open func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) { + adapt(urlRequest, for: session, using: adapters, completion: completion) + } + + private func adapt(_ urlRequest: URLRequest, + for session: Session, + using adapters: [RequestAdapter], + completion: @escaping (Result) -> Void) { + var pendingAdapters = adapters + + guard !pendingAdapters.isEmpty else { completion(.success(urlRequest)); return } + + let adapter = pendingAdapters.removeFirst() + + adapter.adapt(urlRequest, for: session) { result in + switch result { + case let .success(urlRequest): + self.adapt(urlRequest, for: session, using: pendingAdapters, completion: completion) + case .failure: + completion(result) + } + } + } + + open func adapt(_ urlRequest: URLRequest, using state: RequestAdapterState, completion: @escaping (Result) -> Void) { + adapt(urlRequest, using: state, adapters: adapters, completion: completion) + } + + private func adapt(_ urlRequest: URLRequest, + using state: RequestAdapterState, + adapters: [RequestAdapter], + completion: @escaping (Result) -> Void) { + var pendingAdapters = adapters + + guard !pendingAdapters.isEmpty else { completion(.success(urlRequest)); return } + + let adapter = pendingAdapters.removeFirst() + + adapter.adapt(urlRequest, using: state) { result in + switch result { + case let .success(urlRequest): + self.adapt(urlRequest, using: state, adapters: pendingAdapters, completion: completion) + case .failure: + completion(result) + } + } + } + + open func retry(_ request: Request, + for session: Session, + dueTo error: Error, + completion: @escaping (RetryResult) -> Void) { + retry(request, for: session, dueTo: error, using: retriers, completion: completion) + } + + private func retry(_ request: Request, + for session: Session, + dueTo error: Error, + using retriers: [RequestRetrier], + completion: @escaping (RetryResult) -> Void) { + var pendingRetriers = retriers + + guard !pendingRetriers.isEmpty else { completion(.doNotRetry); return } + + let retrier = pendingRetriers.removeFirst() + + retrier.retry(request, for: session, dueTo: error) { result in + switch result { + case .retry, .retryWithDelay, .doNotRetryWithError: + completion(result) + case .doNotRetry: + // Only continue to the next retrier if retry was not triggered and no error was encountered + self.retry(request, for: session, dueTo: error, using: pendingRetriers, completion: completion) + } + } + } +} + +#if swift(>=5.5) +extension RequestInterceptor where Self == Interceptor { + /// Creates an `Interceptor` using the provided `AdaptHandler` and `RetryHandler` closures. + /// + /// - Parameters: + /// - adapter: `AdapterHandler`to use to adapt the request. + /// - retrier: `RetryHandler` to use to retry the request. + /// - Returns: The `Interceptor`. + public static func interceptor(adapter: @escaping AdaptHandler, retrier: @escaping RetryHandler) -> Interceptor { + Interceptor(adaptHandler: adapter, retryHandler: retrier) + } + + /// Creates an `Interceptor` using the provided `RequestAdapter` and `RequestRetrier` instances. + /// - Parameters: + /// - adapter: `RequestAdapter` to use to adapt the request + /// - retrier: `RequestRetrier` to use to retry the request. + /// - Returns: The `Interceptor`. + public static func interceptor(adapter: RequestAdapter, retrier: RequestRetrier) -> Interceptor { + Interceptor(adapter: adapter, retrier: retrier) + } + + /// Creates an `Interceptor` using the provided `RequestAdapter`s, `RequestRetrier`s, and `RequestInterceptor`s. + /// - Parameters: + /// - adapters: `RequestAdapter`s to use to adapt the request. These adapters will be run until one fails. + /// - retriers: `RequestRetrier`s to use to retry the request. These retriers will be run one at a time until + /// a retry is triggered. + /// - interceptors: `RequestInterceptor`s to use to intercept the request. + /// - Returns: The `Interceptor`. + public static func interceptor(adapters: [RequestAdapter] = [], + retriers: [RequestRetrier] = [], + interceptors: [RequestInterceptor] = []) -> Interceptor { + Interceptor(adapters: adapters, retriers: retriers, interceptors: interceptors) + } +} +#endif diff --git a/Instagram-Clone/Pods/Alamofire/Source/RequestTaskMap.swift b/Instagram-Clone/Pods/Alamofire/Source/RequestTaskMap.swift new file mode 100644 index 0000000..85b58f3 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/RequestTaskMap.swift @@ -0,0 +1,149 @@ +// +// RequestTaskMap.swift +// +// Copyright (c) 2014-2018 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 maintains a two way, one to one map of `URLSessionTask`s to `Request`s. +struct RequestTaskMap { + private typealias Events = (completed: Bool, metricsGathered: Bool) + + private var tasksToRequests: [URLSessionTask: Request] + private var requestsToTasks: [Request: URLSessionTask] + private var taskEvents: [URLSessionTask: Events] + + var requests: [Request] { + Array(tasksToRequests.values) + } + + init(tasksToRequests: [URLSessionTask: Request] = [:], + requestsToTasks: [Request: URLSessionTask] = [:], + taskEvents: [URLSessionTask: (completed: Bool, metricsGathered: Bool)] = [:]) { + self.tasksToRequests = tasksToRequests + self.requestsToTasks = requestsToTasks + self.taskEvents = taskEvents + } + + subscript(_ request: Request) -> URLSessionTask? { + get { requestsToTasks[request] } + set { + guard let newValue = newValue else { + guard let task = requestsToTasks[request] else { + fatalError("RequestTaskMap consistency error: no task corresponding to request found.") + } + + requestsToTasks.removeValue(forKey: request) + tasksToRequests.removeValue(forKey: task) + taskEvents.removeValue(forKey: task) + + return + } + + requestsToTasks[request] = newValue + tasksToRequests[newValue] = request + taskEvents[newValue] = (completed: false, metricsGathered: false) + } + } + + subscript(_ task: URLSessionTask) -> Request? { + get { tasksToRequests[task] } + set { + guard let newValue = newValue else { + guard let request = tasksToRequests[task] else { + fatalError("RequestTaskMap consistency error: no request corresponding to task found.") + } + + tasksToRequests.removeValue(forKey: task) + requestsToTasks.removeValue(forKey: request) + taskEvents.removeValue(forKey: task) + + return + } + + tasksToRequests[task] = newValue + requestsToTasks[newValue] = task + taskEvents[task] = (completed: false, metricsGathered: false) + } + } + + var count: Int { + precondition(tasksToRequests.count == requestsToTasks.count, + "RequestTaskMap.count invalid, requests.count: \(tasksToRequests.count) != tasks.count: \(requestsToTasks.count)") + + return tasksToRequests.count + } + + var eventCount: Int { + precondition(taskEvents.count == count, "RequestTaskMap.eventCount invalid, count: \(count) != taskEvents.count: \(taskEvents.count)") + + return taskEvents.count + } + + var isEmpty: Bool { + precondition(tasksToRequests.isEmpty == requestsToTasks.isEmpty, + "RequestTaskMap.isEmpty invalid, requests.isEmpty: \(tasksToRequests.isEmpty) != tasks.isEmpty: \(requestsToTasks.isEmpty)") + + return tasksToRequests.isEmpty + } + + var isEventsEmpty: Bool { + precondition(taskEvents.isEmpty == isEmpty, "RequestTaskMap.isEventsEmpty invalid, isEmpty: \(isEmpty) != taskEvents.isEmpty: \(taskEvents.isEmpty)") + + return taskEvents.isEmpty + } + + mutating func disassociateIfNecessaryAfterGatheringMetricsForTask(_ task: URLSessionTask) -> Bool { + guard let events = taskEvents[task] else { + fatalError("RequestTaskMap consistency error: no events corresponding to task found.") + } + + switch (events.completed, events.metricsGathered) { + case (_, true): fatalError("RequestTaskMap consistency error: duplicate metricsGatheredForTask call.") + case (false, false): taskEvents[task] = (completed: false, metricsGathered: true); return false + case (true, false): self[task] = nil; return true + } + } + + mutating func disassociateIfNecessaryAfterCompletingTask(_ task: URLSessionTask) -> Bool { + guard let events = taskEvents[task] else { + fatalError("RequestTaskMap consistency error: no events corresponding to task found.") + } + + switch (events.completed, events.metricsGathered) { + case (true, _): fatalError("RequestTaskMap consistency error: duplicate completionReceivedForTask call.") + #if os(Linux) // Linux doesn't gather metrics, so unconditionally remove the reference and return true. + default: self[task] = nil; return true + #else + case (false, false): + if #available(macOS 10.12, iOS 10, watchOS 7, tvOS 10, *) { + taskEvents[task] = (completed: true, metricsGathered: false); return false + } else { + // watchOS < 7 doesn't gather metrics, so unconditionally remove the reference and return true. + self[task] = nil; return true + } + case (false, true): + self[task] = nil; return true + #endif + } + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/Response.swift b/Instagram-Clone/Pods/Alamofire/Source/Response.swift new file mode 100644 index 0000000..d9ae9d8 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/Response.swift @@ -0,0 +1,453 @@ +// +// Response.swift +// +// Copyright (c) 2014-2018 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 + +/// Default type of `DataResponse` returned by Alamofire, with an `AFError` `Failure` type. +public typealias AFDataResponse = DataResponse +/// Default type of `DownloadResponse` returned by Alamofire, with an `AFError` `Failure` type. +public typealias AFDownloadResponse = DownloadResponse + +/// Type used to store all values associated with a serialized response of a `DataRequest` or `UploadRequest`. +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 final metrics of the response. + /// + /// - Note: Due to `FB7624529`, collection of `URLSessionTaskMetrics` on watchOS is currently disabled.` + /// + public let metrics: URLSessionTaskMetrics? + + /// The time taken to serialize the response. + public let serializationDuration: TimeInterval + + /// The result of response serialization. + public let result: Result + + /// Returns the associated value of the result if it is a success, `nil` otherwise. + public var value: Success? { result.success } + + /// Returns the associated error value if the result if it is a failure, `nil` otherwise. + public var error: Failure? { result.failure } + + /// Creates a `DataResponse` instance with the specified parameters derived from the response serialization. + /// + /// - Parameters: + /// - request: The `URLRequest` sent to the server. + /// - response: The `HTTPURLResponse` from the server. + /// - data: The `Data` returned by the server. + /// - metrics: The `URLSessionTaskMetrics` of the `DataRequest` or `UploadRequest`. + /// - serializationDuration: The duration taken by serialization. + /// - result: The `Result` of response serialization. + public init(request: URLRequest?, + response: HTTPURLResponse?, + data: Data?, + metrics: URLSessionTaskMetrics?, + serializationDuration: TimeInterval, + result: Result) { + self.request = request + self.response = response + self.data = data + self.metrics = metrics + self.serializationDuration = serializationDuration + self.result = result + } +} + +// 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 { + "\(result)" + } + + /// The debug textual representation used when written to an output stream, which includes (if available) a summary + /// of the `URLRequest`, the request's headers and body (if decodable as a `String` below 100KB); the + /// `HTTPURLResponse`'s status code, headers, and body; the duration of the network and serialization actions; and + /// the `Result` of serialization. + public var debugDescription: String { + guard let urlRequest = request else { return "[Request]: None\n[Result]: \(result)" } + + let requestDescription = DebugDescription.description(of: urlRequest) + + let responseDescription = response.map { response in + let responseBodyDescription = DebugDescription.description(for: data, headers: response.headers) + + return """ + \(DebugDescription.description(of: response)) + \(responseBodyDescription.indentingNewlines()) + """ + } ?? "[Response]: None" + + let networkDuration = metrics.map { "\($0.taskInterval.duration)s" } ?? "None" + + return """ + \(requestDescription) + \(responseDescription) + [Network Duration]: \(networkDuration) + [Serialization Duration]: \(serializationDuration)s + [Result]: \(result) + """ + } +} + +// 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: (Success) -> NewSuccess) -> DataResponse { + DataResponse(request: request, + response: response, + data: data, + metrics: metrics, + serializationDuration: serializationDuration, + result: result.map(transform)) + } + + /// Evaluates the given closure when the result of this `DataResponse` is a success, passing the unwrapped result + /// value as a parameter. + /// + /// Use the `tryMap` method with a closure that may throw an error. For example: + /// + /// let possibleData: DataResponse = ... + /// let possibleObject = possibleData.tryMap { + /// 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 tryMap(_ transform: (Success) throws -> NewSuccess) -> DataResponse { + DataResponse(request: request, + response: response, + data: data, + metrics: metrics, + serializationDuration: serializationDuration, + result: result.tryMap(transform)) + } + + /// 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: (Failure) -> NewFailure) -> DataResponse { + DataResponse(request: request, + response: response, + data: data, + metrics: metrics, + serializationDuration: serializationDuration, + result: result.mapError(transform)) + } + + /// Evaluates the specified closure when the `DataResponse` is a failure, passing the unwrapped error as a parameter. + /// + /// Use the `tryMapError` function with a closure that may throw an error. For example: + /// + /// let possibleData: DataResponse = ... + /// let possibleObject = possibleData.tryMapError { + /// 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 tryMapError(_ transform: (Failure) throws -> NewFailure) -> DataResponse { + DataResponse(request: request, + response: response, + data: data, + metrics: metrics, + serializationDuration: serializationDuration, + result: result.tryMapError(transform)) + } +} + +// 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 final destination URL of the data returned from the server after it is moved. + public let fileURL: URL? + + /// The resume data generated if the request was cancelled. + public let resumeData: Data? + + /// The final metrics of the response. + /// + /// - Note: Due to `FB7624529`, collection of `URLSessionTaskMetrics` on watchOS is currently disabled.` + /// + public let metrics: URLSessionTaskMetrics? + + /// The time taken to serialize the response. + public let serializationDuration: TimeInterval + + /// The result of response serialization. + public let result: Result + + /// Returns the associated value of the result if it is a success, `nil` otherwise. + public var value: Success? { result.success } + + /// Returns the associated error value if the result if it is a failure, `nil` otherwise. + public var error: Failure? { result.failure } + + /// Creates a `DownloadResponse` instance with the specified parameters derived from response serialization. + /// + /// - Parameters: + /// - request: The `URLRequest` sent to the server. + /// - response: The `HTTPURLResponse` from the server. + /// - fileURL: The final destination URL of the data returned from the server after it is moved. + /// - resumeData: The resume `Data` generated if the request was cancelled. + /// - metrics: The `URLSessionTaskMetrics` of the `DownloadRequest`. + /// - serializationDuration: The duration taken by serialization. + /// - result: The `Result` of response serialization. + public init(request: URLRequest?, + response: HTTPURLResponse?, + fileURL: URL?, + resumeData: Data?, + metrics: URLSessionTaskMetrics?, + serializationDuration: TimeInterval, + result: Result) { + self.request = request + self.response = response + self.fileURL = fileURL + self.resumeData = resumeData + self.metrics = metrics + self.serializationDuration = serializationDuration + self.result = result + } +} + +// 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 { + "\(result)" + } + + /// 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 durations of the network and serialization + /// actions, and the response serialization result. + public var debugDescription: String { + guard let urlRequest = request else { return "[Request]: None\n[Result]: \(result)" } + + let requestDescription = DebugDescription.description(of: urlRequest) + let responseDescription = response.map(DebugDescription.description(of:)) ?? "[Response]: None" + let networkDuration = metrics.map { "\($0.taskInterval.duration)s" } ?? "None" + let resumeDataDescription = resumeData.map { "\($0)" } ?? "None" + + return """ + \(requestDescription) + \(responseDescription) + [File URL]: \(fileURL?.path ?? "None") + [Resume Data]: \(resumeDataDescription) + [Network Duration]: \(networkDuration) + [Serialization Duration]: \(serializationDuration)s + [Result]: \(result) + """ + } +} + +// 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: (Success) -> NewSuccess) -> DownloadResponse { + DownloadResponse(request: request, + response: response, + fileURL: fileURL, + resumeData: resumeData, + metrics: metrics, + serializationDuration: serializationDuration, + result: result.map(transform)) + } + + /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped + /// result value as a parameter. + /// + /// Use the `tryMap` method with a closure that may throw an error. For example: + /// + /// let possibleData: DownloadResponse = ... + /// let possibleObject = possibleData.tryMap { + /// 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 tryMap(_ transform: (Success) throws -> NewSuccess) -> DownloadResponse { + DownloadResponse(request: request, + response: response, + fileURL: fileURL, + resumeData: resumeData, + metrics: metrics, + serializationDuration: serializationDuration, + result: result.tryMap(transform)) + } + + /// 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: (Failure) -> NewFailure) -> DownloadResponse { + DownloadResponse(request: request, + response: response, + fileURL: fileURL, + resumeData: resumeData, + metrics: metrics, + serializationDuration: serializationDuration, + result: result.mapError(transform)) + } + + /// Evaluates the specified closure when the `DownloadResponse` is a failure, passing the unwrapped error as a parameter. + /// + /// Use the `tryMapError` function with a closure that may throw an error. For example: + /// + /// let possibleData: DownloadResponse = ... + /// let possibleObject = possibleData.tryMapError { + /// 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 tryMapError(_ transform: (Failure) throws -> NewFailure) -> DownloadResponse { + DownloadResponse(request: request, + response: response, + fileURL: fileURL, + resumeData: resumeData, + metrics: metrics, + serializationDuration: serializationDuration, + result: result.tryMapError(transform)) + } +} + +private enum DebugDescription { + static func description(of request: URLRequest) -> String { + let requestSummary = "\(request.httpMethod!) \(request)" + let requestHeadersDescription = DebugDescription.description(for: request.headers) + let requestBodyDescription = DebugDescription.description(for: request.httpBody, headers: request.headers) + + return """ + [Request]: \(requestSummary) + \(requestHeadersDescription.indentingNewlines()) + \(requestBodyDescription.indentingNewlines()) + """ + } + + static func description(of response: HTTPURLResponse) -> String { + """ + [Response]: + [Status Code]: \(response.statusCode) + \(DebugDescription.description(for: response.headers).indentingNewlines()) + """ + } + + static func description(for headers: HTTPHeaders) -> String { + guard !headers.isEmpty else { return "[Headers]: None" } + + let headerDescription = "\(headers.sorted())".indentingNewlines() + return """ + [Headers]: + \(headerDescription) + """ + } + + static func description(for data: Data?, + headers: HTTPHeaders, + allowingPrintableTypes printableTypes: [String] = ["json", "xml", "text"], + maximumLength: Int = 100_000) -> String { + guard let data = data, !data.isEmpty else { return "[Body]: None" } + + guard + data.count <= maximumLength, + printableTypes.compactMap({ headers["Content-Type"]?.contains($0) }).contains(true) + else { return "[Body]: \(data.count) bytes" } + + return """ + [Body]: + \(String(decoding: data, as: UTF8.self) + .trimmingCharacters(in: .whitespacesAndNewlines) + .indentingNewlines()) + """ + } +} + +extension String { + fileprivate func indentingNewlines(by spaceCount: Int = 4) -> String { + let spaces = String(repeating: " ", count: spaceCount) + return replacingOccurrences(of: "\n", with: "\n\(spaces)") + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/ResponseSerialization.swift b/Instagram-Clone/Pods/Alamofire/Source/ResponseSerialization.swift new file mode 100644 index 0000000..3097364 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/ResponseSerialization.swift @@ -0,0 +1,1290 @@ +// +// ResponseSerialization.swift +// +// Copyright (c) 2014-2018 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 + +// MARK: Protocols + +/// The type to which all data response serializers must conform in order to serialize a response. +public protocol DataResponseSerializerProtocol { + /// The type of serialized object to be created. + associatedtype SerializedObject + + /// Serialize the response `Data` into the provided type.. + /// + /// - Parameters: + /// - request: `URLRequest` which was used to perform the request, if any. + /// - response: `HTTPURLResponse` received from the server, if any. + /// - data: `Data` returned from the server, if any. + /// - error: `Error` produced by Alamofire or the underlying `URLSession` during the request. + /// + /// - Returns: The `SerializedObject`. + /// - Throws: Any `Error` produced during serialization. + func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> SerializedObject +} + +/// The type to which all download response serializers must conform in order to serialize a response. +public protocol DownloadResponseSerializerProtocol { + /// The type of serialized object to be created. + associatedtype SerializedObject + + /// Serialize the downloaded response `Data` from disk into the provided type.. + /// + /// - Parameters: + /// - request: `URLRequest` which was used to perform the request, if any. + /// - response: `HTTPURLResponse` received from the server, if any. + /// - fileURL: File `URL` to which the response data was downloaded. + /// - error: `Error` produced by Alamofire or the underlying `URLSession` during the request. + /// + /// - Returns: The `SerializedObject`. + /// - Throws: Any `Error` produced during serialization. + func serializeDownload(request: URLRequest?, response: HTTPURLResponse?, fileURL: URL?, error: Error?) throws -> SerializedObject +} + +/// A serializer that can handle both data and download responses. +public protocol ResponseSerializer: DataResponseSerializerProtocol & DownloadResponseSerializerProtocol { + /// `DataPreprocessor` used to prepare incoming `Data` for serialization. + var dataPreprocessor: DataPreprocessor { get } + /// `HTTPMethod`s for which empty response bodies are considered appropriate. + var emptyRequestMethods: Set { get } + /// HTTP response codes for which empty response bodies are considered appropriate. + var emptyResponseCodes: Set { get } +} + +/// Type used to preprocess `Data` before it handled by a serializer. +public protocol DataPreprocessor { + /// Process `Data` before it's handled by a serializer. + /// - Parameter data: The raw `Data` to process. + func preprocess(_ data: Data) throws -> Data +} + +/// `DataPreprocessor` that returns passed `Data` without any transform. +public struct PassthroughPreprocessor: DataPreprocessor { + public init() {} + + public func preprocess(_ data: Data) throws -> Data { data } +} + +/// `DataPreprocessor` that trims Google's typical `)]}',\n` XSSI JSON header. +public struct GoogleXSSIPreprocessor: DataPreprocessor { + public init() {} + + public func preprocess(_ data: Data) throws -> Data { + (data.prefix(6) == Data(")]}',\n".utf8)) ? data.dropFirst(6) : data + } +} + +#if swift(>=5.5) +extension DataPreprocessor where Self == PassthroughPreprocessor { + /// Provides a `PassthroughPreprocessor` instance. + public static var passthrough: PassthroughPreprocessor { PassthroughPreprocessor() } +} + +extension DataPreprocessor where Self == GoogleXSSIPreprocessor { + /// Provides a `GoogleXSSIPreprocessor` instance. + public static var googleXSSI: GoogleXSSIPreprocessor { GoogleXSSIPreprocessor() } +} +#endif + +extension ResponseSerializer { + /// Default `DataPreprocessor`. `PassthroughPreprocessor` by default. + public static var defaultDataPreprocessor: DataPreprocessor { PassthroughPreprocessor() } + /// Default `HTTPMethod`s for which empty response bodies are considered appropriate. `[.head]` by default. + public static var defaultEmptyRequestMethods: Set { [.head] } + /// HTTP response codes for which empty response bodies are considered appropriate. `[204, 205]` by default. + public static var defaultEmptyResponseCodes: Set { [204, 205] } + + public var dataPreprocessor: DataPreprocessor { Self.defaultDataPreprocessor } + public var emptyRequestMethods: Set { Self.defaultEmptyRequestMethods } + public var emptyResponseCodes: Set { Self.defaultEmptyResponseCodes } + + /// Determines whether the `request` allows empty response bodies, if `request` exists. + /// + /// - Parameter request: `URLRequest` to evaluate. + /// + /// - Returns: `Bool` representing the outcome of the evaluation, or `nil` if `request` was `nil`. + public func requestAllowsEmptyResponseData(_ request: URLRequest?) -> Bool? { + request.flatMap(\.httpMethod) + .flatMap(HTTPMethod.init) + .map { emptyRequestMethods.contains($0) } + } + + /// Determines whether the `response` allows empty response bodies, if `response` exists`. + /// + /// - Parameter response: `HTTPURLResponse` to evaluate. + /// + /// - Returns: `Bool` representing the outcome of the evaluation, or `nil` if `response` was `nil`. + public func responseAllowsEmptyResponseData(_ response: HTTPURLResponse?) -> Bool? { + response.map(\.statusCode) + .map { emptyResponseCodes.contains($0) } + } + + /// Determines whether `request` and `response` allow empty response bodies. + /// + /// - Parameters: + /// - request: `URLRequest` to evaluate. + /// - response: `HTTPURLResponse` to evaluate. + /// + /// - Returns: `true` if `request` or `response` allow empty bodies, `false` otherwise. + public func emptyResponseAllowed(forRequest request: URLRequest?, response: HTTPURLResponse?) -> Bool { + (requestAllowsEmptyResponseData(request) == true) || (responseAllowsEmptyResponseData(response) == true) + } +} + +/// By default, any serializer declared to conform to both types will get file serialization for free, as it just feeds +/// the data read from disk into the data response serializer. +extension DownloadResponseSerializerProtocol where Self: DataResponseSerializerProtocol { + public func serializeDownload(request: URLRequest?, response: HTTPURLResponse?, fileURL: URL?, error: Error?) throws -> Self.SerializedObject { + guard error == nil else { throw error! } + + guard let fileURL = fileURL else { + throw AFError.responseSerializationFailed(reason: .inputFileNil) + } + + let data: Data + do { + data = try Data(contentsOf: fileURL) + } catch { + throw AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL)) + } + + do { + return try serialize(request: request, response: response, data: data, error: error) + } catch { + throw error + } + } +} + +// MARK: - Default + +extension DataRequest { + /// Adds a handler to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is dispatched. `.main` by default. + /// - completionHandler: The code to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func response(queue: DispatchQueue = .main, completionHandler: @escaping (AFDataResponse) -> Void) -> Self { + appendResponseSerializer { + // Start work that should be on the serialization queue. + let result = AFResult(value: self.data, error: self.error) + // End work that should be on the serialization queue. + + self.underlyingQueue.async { + let response = DataResponse(request: self.request, + response: self.response, + data: self.data, + metrics: self.metrics, + serializationDuration: 0, + result: result) + + self.eventMonitor?.request(self, didParseResponse: response) + + self.responseSerializerDidComplete { queue.async { completionHandler(response) } } + } + } + + return self + } + + private func _response(queue: DispatchQueue = .main, + responseSerializer: Serializer, + completionHandler: @escaping (AFDataResponse) -> Void) + -> Self { + appendResponseSerializer { + // Start work that should be on the serialization queue. + let start = ProcessInfo.processInfo.systemUptime + let result: AFResult = Result { + try responseSerializer.serialize(request: self.request, + response: self.response, + data: self.data, + error: self.error) + }.mapError { error in + error.asAFError(or: .responseSerializationFailed(reason: .customSerializationFailed(error: error))) + } + + let end = ProcessInfo.processInfo.systemUptime + // End work that should be on the serialization queue. + + self.underlyingQueue.async { + let response = DataResponse(request: self.request, + response: self.response, + data: self.data, + metrics: self.metrics, + serializationDuration: end - start, + result: result) + + self.eventMonitor?.request(self, didParseResponse: response) + + guard let serializerError = result.failure, let delegate = self.delegate else { + self.responseSerializerDidComplete { queue.async { completionHandler(response) } } + return + } + + delegate.retryResult(for: self, dueTo: serializerError) { retryResult in + var didComplete: (() -> Void)? + + defer { + if let didComplete = didComplete { + self.responseSerializerDidComplete { queue.async { didComplete() } } + } + } + + switch retryResult { + case .doNotRetry: + didComplete = { completionHandler(response) } + + case let .doNotRetryWithError(retryError): + let result: AFResult = .failure(retryError.asAFError(orFailWith: "Received retryError was not already AFError")) + + let response = DataResponse(request: self.request, + response: self.response, + data: self.data, + metrics: self.metrics, + serializationDuration: end - start, + result: result) + + didComplete = { completionHandler(response) } + + case .retry, .retryWithDelay: + delegate.retryRequest(self, withDelay: retryResult.delay) + } + } + } + } + + return self + } + + /// Adds a handler to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is dispatched. `.main` by default + /// - responseSerializer: The response serializer responsible for serializing the request, response, and data. + /// - completionHandler: The code to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func response(queue: DispatchQueue = .main, + responseSerializer: Serializer, + completionHandler: @escaping (AFDataResponse) -> Void) + -> Self { + _response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler) + } + + /// Adds a handler to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is dispatched. `.main` by default + /// - responseSerializer: The response serializer responsible for serializing the request, response, and data. + /// - completionHandler: The code to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func response(queue: DispatchQueue = .main, + responseSerializer: Serializer, + completionHandler: @escaping (AFDataResponse) -> Void) + -> Self { + _response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler) + } +} + +extension DownloadRequest { + /// Adds a handler to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is dispatched. `.main` by default. + /// - completionHandler: The code to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func response(queue: DispatchQueue = .main, + completionHandler: @escaping (AFDownloadResponse) -> Void) + -> Self { + appendResponseSerializer { + // Start work that should be on the serialization queue. + let result = AFResult(value: self.fileURL, error: self.error) + // End work that should be on the serialization queue. + + self.underlyingQueue.async { + let response = DownloadResponse(request: self.request, + response: self.response, + fileURL: self.fileURL, + resumeData: self.resumeData, + metrics: self.metrics, + serializationDuration: 0, + result: result) + + self.eventMonitor?.request(self, didParseResponse: response) + + self.responseSerializerDidComplete { queue.async { completionHandler(response) } } + } + } + + return self + } + + private func _response(queue: DispatchQueue = .main, + responseSerializer: Serializer, + completionHandler: @escaping (AFDownloadResponse) -> Void) + -> Self { + appendResponseSerializer { + // Start work that should be on the serialization queue. + let start = ProcessInfo.processInfo.systemUptime + let result: AFResult = Result { + try responseSerializer.serializeDownload(request: self.request, + response: self.response, + fileURL: self.fileURL, + error: self.error) + }.mapError { error in + error.asAFError(or: .responseSerializationFailed(reason: .customSerializationFailed(error: error))) + } + let end = ProcessInfo.processInfo.systemUptime + // End work that should be on the serialization queue. + + self.underlyingQueue.async { + let response = DownloadResponse(request: self.request, + response: self.response, + fileURL: self.fileURL, + resumeData: self.resumeData, + metrics: self.metrics, + serializationDuration: end - start, + result: result) + + self.eventMonitor?.request(self, didParseResponse: response) + + guard let serializerError = result.failure, let delegate = self.delegate else { + self.responseSerializerDidComplete { queue.async { completionHandler(response) } } + return + } + + delegate.retryResult(for: self, dueTo: serializerError) { retryResult in + var didComplete: (() -> Void)? + + defer { + if let didComplete = didComplete { + self.responseSerializerDidComplete { queue.async { didComplete() } } + } + } + + switch retryResult { + case .doNotRetry: + didComplete = { completionHandler(response) } + + case let .doNotRetryWithError(retryError): + let result: AFResult = .failure(retryError.asAFError(orFailWith: "Received retryError was not already AFError")) + + let response = DownloadResponse(request: self.request, + response: self.response, + fileURL: self.fileURL, + resumeData: self.resumeData, + metrics: self.metrics, + serializationDuration: end - start, + result: result) + + didComplete = { completionHandler(response) } + + case .retry, .retryWithDelay: + delegate.retryRequest(self, withDelay: retryResult.delay) + } + } + } + } + + return self + } + + /// Adds a handler to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is dispatched. `.main` by default. + /// - responseSerializer: The response serializer responsible for serializing the request, response, and data + /// contained in the destination `URL`. + /// - completionHandler: The code to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func response(queue: DispatchQueue = .main, + responseSerializer: Serializer, + completionHandler: @escaping (AFDownloadResponse) -> Void) + -> Self { + _response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler) + } + + /// Adds a handler to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is dispatched. `.main` by default. + /// - responseSerializer: The response serializer responsible for serializing the request, response, and data + /// contained in the destination `URL`. + /// - completionHandler: The code to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func response(queue: DispatchQueue = .main, + responseSerializer: Serializer, + completionHandler: @escaping (AFDownloadResponse) -> Void) + -> Self { + _response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler) + } +} + +// MARK: - URL + +/// A `DownloadResponseSerializerProtocol` that performs only `Error` checking and ensures that a downloaded `fileURL` +/// is present. +public struct URLResponseSerializer: DownloadResponseSerializerProtocol { + /// Creates an instance. + public init() {} + + public func serializeDownload(request: URLRequest?, + response: HTTPURLResponse?, + fileURL: URL?, + error: Error?) throws -> URL { + guard error == nil else { throw error! } + + guard let url = fileURL else { + throw AFError.responseSerializationFailed(reason: .inputFileNil) + } + + return url + } +} + +#if swift(>=5.5) +extension DownloadResponseSerializerProtocol where Self == URLResponseSerializer { + /// Provides a `URLResponseSerializer` instance. + public static var url: URLResponseSerializer { URLResponseSerializer() } +} +#endif + +extension DownloadRequest { + /// Adds a handler using a `URLResponseSerializer` to be called once the request is finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is called. `.main` by default. + /// - completionHandler: A closure to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func responseURL(queue: DispatchQueue = .main, + completionHandler: @escaping (AFDownloadResponse) -> Void) -> Self { + response(queue: queue, responseSerializer: URLResponseSerializer(), completionHandler: completionHandler) + } +} + +// MARK: - Data + +/// A `ResponseSerializer` that performs minimal response checking and returns any response `Data` as-is. By default, a +/// request returning `nil` or no data is considered an error. However, if the request has an `HTTPMethod` or the +/// response has an HTTP status code valid for empty responses, then an empty `Data` value is returned. +public final class DataResponseSerializer: ResponseSerializer { + public let dataPreprocessor: DataPreprocessor + public let emptyResponseCodes: Set + public let emptyRequestMethods: Set + + /// Creates a `DataResponseSerializer` using the provided parameters. + /// + /// - Parameters: + /// - dataPreprocessor: `DataPreprocessor` used to prepare the received `Data` for serialization. + /// - emptyResponseCodes: The HTTP response codes for which empty responses are allowed. `[204, 205]` by default. + /// - emptyRequestMethods: The HTTP request methods for which empty responses are allowed. `[.head]` by default. + public init(dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods) { + self.dataPreprocessor = dataPreprocessor + self.emptyResponseCodes = emptyResponseCodes + self.emptyRequestMethods = emptyRequestMethods + } + + public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Data { + guard error == nil else { throw error! } + + guard var data = data, !data.isEmpty else { + guard emptyResponseAllowed(forRequest: request, response: response) else { + throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength) + } + + return Data() + } + + data = try dataPreprocessor.preprocess(data) + + return data + } +} + +#if swift(>=5.5) +extension ResponseSerializer where Self == DataResponseSerializer { + /// Provides a default `DataResponseSerializer` instance. + public static var data: DataResponseSerializer { DataResponseSerializer() } + + /// Creates a `DataResponseSerializer` using the provided parameters. + /// + /// - Parameters: + /// - dataPreprocessor: `DataPreprocessor` used to prepare the received `Data` for serialization. + /// - emptyResponseCodes: The HTTP response codes for which empty responses are allowed. `[204, 205]` by default. + /// - emptyRequestMethods: The HTTP request methods for which empty responses are allowed. `[.head]` by default. + /// + /// - Returns: The `DataResponseSerializer`. + public static func data(dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods) -> DataResponseSerializer { + DataResponseSerializer(dataPreprocessor: dataPreprocessor, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods) + } +} +#endif + +extension DataRequest { + /// Adds a handler using a `DataResponseSerializer` to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is called. `.main` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the + /// `completionHandler`. `PassthroughPreprocessor()` by default. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// - completionHandler: A closure to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func responseData(queue: DispatchQueue = .main, + dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods, + completionHandler: @escaping (AFDataResponse) -> Void) -> Self { + response(queue: queue, + responseSerializer: DataResponseSerializer(dataPreprocessor: dataPreprocessor, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + completionHandler: completionHandler) + } +} + +extension DownloadRequest { + /// Adds a handler using a `DataResponseSerializer` to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is called. `.main` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the + /// `completionHandler`. `PassthroughPreprocessor()` by default. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// - completionHandler: A closure to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func responseData(queue: DispatchQueue = .main, + dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = DataResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DataResponseSerializer.defaultEmptyRequestMethods, + completionHandler: @escaping (AFDownloadResponse) -> Void) -> Self { + response(queue: queue, + responseSerializer: DataResponseSerializer(dataPreprocessor: dataPreprocessor, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + completionHandler: completionHandler) + } +} + +// MARK: - String + +/// A `ResponseSerializer` that decodes the response data as a `String`. By default, a request returning `nil` or no +/// data is considered an error. However, if the request has an `HTTPMethod` or the response has an HTTP status code +/// valid for empty responses, then an empty `String` is returned. +public final class StringResponseSerializer: ResponseSerializer { + public let dataPreprocessor: DataPreprocessor + /// Optional string encoding used to validate the response. + public let encoding: String.Encoding? + public let emptyResponseCodes: Set + public let emptyRequestMethods: Set + + /// Creates an instance with the provided values. + /// + /// - Parameters: + /// - dataPreprocessor: `DataPreprocessor` used to prepare the received `Data` for serialization. + /// - encoding: A string encoding. Defaults to `nil`, in which case the encoding will be determined + /// from the server response, falling back to the default HTTP character set, `ISO-8859-1`. + /// - emptyResponseCodes: The HTTP response codes for which empty responses are allowed. `[204, 205]` by default. + /// - emptyRequestMethods: The HTTP request methods for which empty responses are allowed. `[.head]` by default. + public init(dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor, + encoding: String.Encoding? = nil, + emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = StringResponseSerializer.defaultEmptyRequestMethods) { + self.dataPreprocessor = dataPreprocessor + self.encoding = encoding + self.emptyResponseCodes = emptyResponseCodes + self.emptyRequestMethods = emptyRequestMethods + } + + public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> String { + guard error == nil else { throw error! } + + guard var data = data, !data.isEmpty else { + guard emptyResponseAllowed(forRequest: request, response: response) else { + throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength) + } + + return "" + } + + data = try dataPreprocessor.preprocess(data) + + var convertedEncoding = encoding + + if let encodingName = response?.textEncodingName, convertedEncoding == nil { + convertedEncoding = String.Encoding(ianaCharsetName: encodingName) + } + + let actualEncoding = convertedEncoding ?? .isoLatin1 + + guard let string = String(data: data, encoding: actualEncoding) else { + throw AFError.responseSerializationFailed(reason: .stringSerializationFailed(encoding: actualEncoding)) + } + + return string + } +} + +#if swift(>=5.5) +extension ResponseSerializer where Self == StringResponseSerializer { + /// Provides a default `StringResponseSerializer` instance. + public static var string: StringResponseSerializer { StringResponseSerializer() } + + /// Creates a `StringResponseSerializer` with the provided values. + /// + /// - Parameters: + /// - dataPreprocessor: `DataPreprocessor` used to prepare the received `Data` for serialization. + /// - encoding: A string encoding. Defaults to `nil`, in which case the encoding will be determined + /// from the server response, falling back to the default HTTP character set, `ISO-8859-1`. + /// - emptyResponseCodes: The HTTP response codes for which empty responses are allowed. `[204, 205]` by default. + /// - emptyRequestMethods: The HTTP request methods for which empty responses are allowed. `[.head]` by default. + /// + /// - Returns: The `StringResponseSerializer`. + public static func string(dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor, + encoding: String.Encoding? = nil, + emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = StringResponseSerializer.defaultEmptyRequestMethods) -> StringResponseSerializer { + StringResponseSerializer(dataPreprocessor: dataPreprocessor, + encoding: encoding, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods) + } +} +#endif + +extension DataRequest { + /// Adds a handler using a `StringResponseSerializer` to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is dispatched. `.main` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the + /// `completionHandler`. `PassthroughPreprocessor()` by default. + /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined + /// from the server response, falling back to the default HTTP character set, `ISO-8859-1`. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// - completionHandler: A closure to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func responseString(queue: DispatchQueue = .main, + dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor, + encoding: String.Encoding? = nil, + emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = StringResponseSerializer.defaultEmptyRequestMethods, + completionHandler: @escaping (AFDataResponse) -> Void) -> Self { + response(queue: queue, + responseSerializer: StringResponseSerializer(dataPreprocessor: dataPreprocessor, + encoding: encoding, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + completionHandler: completionHandler) + } +} + +extension DownloadRequest { + /// Adds a handler using a `StringResponseSerializer` to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is dispatched. `.main` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the + /// `completionHandler`. `PassthroughPreprocessor()` by default. + /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined + /// from the server response, falling back to the default HTTP character set, `ISO-8859-1`. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// - completionHandler: A closure to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func responseString(queue: DispatchQueue = .main, + dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor, + encoding: String.Encoding? = nil, + emptyResponseCodes: Set = StringResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = StringResponseSerializer.defaultEmptyRequestMethods, + completionHandler: @escaping (AFDownloadResponse) -> Void) -> Self { + response(queue: queue, + responseSerializer: StringResponseSerializer(dataPreprocessor: dataPreprocessor, + encoding: encoding, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + completionHandler: completionHandler) + } +} + +// MARK: - JSON + +/// A `ResponseSerializer` that decodes the response data using `JSONSerialization`. By default, a request returning +/// `nil` or no data is considered an error. However, if the request has an `HTTPMethod` or the response has an +/// HTTP status code valid for empty responses, then an `NSNull` value is returned. +@available(*, deprecated, message: "JSONResponseSerializer deprecated and will be removed in Alamofire 6. Use DecodableResponseSerializer instead.") +public final class JSONResponseSerializer: ResponseSerializer { + public let dataPreprocessor: DataPreprocessor + public let emptyResponseCodes: Set + public let emptyRequestMethods: Set + /// `JSONSerialization.ReadingOptions` used when serializing a response. + public let options: JSONSerialization.ReadingOptions + + /// Creates an instance with the provided values. + /// + /// - Parameters: + /// - dataPreprocessor: `DataPreprocessor` used to prepare the received `Data` for serialization. + /// - emptyResponseCodes: The HTTP response codes for which empty responses are allowed. `[204, 205]` by default. + /// - emptyRequestMethods: The HTTP request methods for which empty responses are allowed. `[.head]` by default. + /// - options: The options to use. `.allowFragments` by default. + public init(dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = JSONResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = JSONResponseSerializer.defaultEmptyRequestMethods, + options: JSONSerialization.ReadingOptions = .allowFragments) { + self.dataPreprocessor = dataPreprocessor + self.emptyResponseCodes = emptyResponseCodes + self.emptyRequestMethods = emptyRequestMethods + self.options = options + } + + public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> Any { + guard error == nil else { throw error! } + + guard var data = data, !data.isEmpty else { + guard emptyResponseAllowed(forRequest: request, response: response) else { + throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength) + } + + return NSNull() + } + + data = try dataPreprocessor.preprocess(data) + + do { + return try JSONSerialization.jsonObject(with: data, options: options) + } catch { + throw AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error)) + } + } +} + +extension DataRequest { + /// Adds a handler using a `JSONResponseSerializer` to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is dispatched. `.main` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the + /// `completionHandler`. `PassthroughPreprocessor()` by default. + /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined + /// from the server response, falling back to the default HTTP character set, `ISO-8859-1`. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// - options: `JSONSerialization.ReadingOptions` used when parsing the response. `.allowFragments` + /// by default. + /// - completionHandler: A closure to be executed once the request has finished. + /// + /// - Returns: The request. + @available(*, deprecated, message: "responseJSON deprecated and will be removed in Alamofire 6. Use responseDecodable instead.") + @discardableResult + public func responseJSON(queue: DispatchQueue = .main, + dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = JSONResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = JSONResponseSerializer.defaultEmptyRequestMethods, + options: JSONSerialization.ReadingOptions = .allowFragments, + completionHandler: @escaping (AFDataResponse) -> Void) -> Self { + response(queue: queue, + responseSerializer: JSONResponseSerializer(dataPreprocessor: dataPreprocessor, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods, + options: options), + completionHandler: completionHandler) + } +} + +extension DownloadRequest { + /// Adds a handler using a `JSONResponseSerializer` to be called once the request has finished. + /// + /// - Parameters: + /// - queue: The queue on which the completion handler is dispatched. `.main` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the + /// `completionHandler`. `PassthroughPreprocessor()` by default. + /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined + /// from the server response, falling back to the default HTTP character set, `ISO-8859-1`. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// - options: `JSONSerialization.ReadingOptions` used when parsing the response. `.allowFragments` + /// by default. + /// - completionHandler: A closure to be executed once the request has finished. + /// + /// - Returns: The request. + @available(*, deprecated, message: "responseJSON deprecated and will be removed in Alamofire 6. Use responseDecodable instead.") + @discardableResult + public func responseJSON(queue: DispatchQueue = .main, + dataPreprocessor: DataPreprocessor = JSONResponseSerializer.defaultDataPreprocessor, + emptyResponseCodes: Set = JSONResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = JSONResponseSerializer.defaultEmptyRequestMethods, + options: JSONSerialization.ReadingOptions = .allowFragments, + completionHandler: @escaping (AFDownloadResponse) -> Void) -> Self { + response(queue: queue, + responseSerializer: JSONResponseSerializer(dataPreprocessor: dataPreprocessor, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods, + options: options), + completionHandler: completionHandler) + } +} + +// MARK: - Empty + +/// Protocol representing an empty response. Use `T.emptyValue()` to get an instance. +public protocol EmptyResponse { + /// Empty value for the conforming type. + /// + /// - Returns: Value of `Self` to use for empty values. + static func emptyValue() -> Self +} + +/// Type representing an empty value. Use `Empty.value` to get the static instance. +public struct Empty: Codable { + /// Static `Empty` instance used for all `Empty` responses. + public static let value = Empty() +} + +extension Empty: EmptyResponse { + public static func emptyValue() -> Empty { + value + } +} + +// MARK: - DataDecoder Protocol + +/// Any type which can decode `Data` into a `Decodable` type. +public protocol DataDecoder { + /// Decode `Data` into the provided type. + /// + /// - Parameters: + /// - type: The `Type` to be decoded. + /// - data: The `Data` to be decoded. + /// + /// - Returns: The decoded value of type `D`. + /// - Throws: Any error that occurs during decode. + func decode(_ type: D.Type, from data: Data) throws -> D +} + +/// `JSONDecoder` automatically conforms to `DataDecoder`. +extension JSONDecoder: DataDecoder {} +/// `PropertyListDecoder` automatically conforms to `DataDecoder`. +extension PropertyListDecoder: DataDecoder {} + +// MARK: - Decodable + +/// A `ResponseSerializer` that decodes the response data as a generic value using any type that conforms to +/// `DataDecoder`. By default, this is an instance of `JSONDecoder`. Additionally, a request returning `nil` or no data +/// is considered an error. However, if the request has an `HTTPMethod` or the response has an HTTP status code valid +/// for empty responses then an empty value will be returned. If the decoded type conforms to `EmptyResponse`, the +/// type's `emptyValue()` will be returned. If the decoded type is `Empty`, the `.value` instance is returned. If the +/// decoded type *does not* conform to `EmptyResponse` and isn't `Empty`, an error will be produced. +public final class DecodableResponseSerializer: ResponseSerializer { + public let dataPreprocessor: DataPreprocessor + /// The `DataDecoder` instance used to decode responses. + public let decoder: DataDecoder + public let emptyResponseCodes: Set + public let emptyRequestMethods: Set + + /// Creates an instance using the values provided. + /// + /// - Parameters: + /// - dataPreprocessor: `DataPreprocessor` used to prepare the received `Data` for serialization. + /// - decoder: The `DataDecoder`. `JSONDecoder()` by default. + /// - emptyResponseCodes: The HTTP response codes for which empty responses are allowed. `[204, 205]` by default. + /// - emptyRequestMethods: The HTTP request methods for which empty responses are allowed. `[.head]` by default. + public init(dataPreprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, + decoder: DataDecoder = JSONDecoder(), + emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods) { + self.dataPreprocessor = dataPreprocessor + self.decoder = decoder + self.emptyResponseCodes = emptyResponseCodes + self.emptyRequestMethods = emptyRequestMethods + } + + public func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> T { + guard error == nil else { throw error! } + + guard var data = data, !data.isEmpty else { + guard emptyResponseAllowed(forRequest: request, response: response) else { + throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength) + } + + guard let emptyResponseType = T.self as? EmptyResponse.Type, let emptyValue = emptyResponseType.emptyValue() as? T else { + throw AFError.responseSerializationFailed(reason: .invalidEmptyResponse(type: "\(T.self)")) + } + + return emptyValue + } + + data = try dataPreprocessor.preprocess(data) + + do { + return try decoder.decode(T.self, from: data) + } catch { + throw AFError.responseSerializationFailed(reason: .decodingFailed(error: error)) + } + } +} + +#if swift(>=5.5) +extension ResponseSerializer { + /// Creates a `DecodableResponseSerializer` using the values provided. + /// + /// - Parameters: + /// - type: `Decodable` type to decode from response data. + /// - dataPreprocessor: `DataPreprocessor` used to prepare the received `Data` for serialization. + /// - decoder: The `DataDecoder`. `JSONDecoder()` by default. + /// - emptyResponseCodes: The HTTP response codes for which empty responses are allowed. `[204, 205]` by default. + /// - emptyRequestMethods: The HTTP request methods for which empty responses are allowed. `[.head]` by default. + /// + /// - Returns: The `DecodableResponseSerializer`. + public static func decodable(of type: T.Type, + dataPreprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, + decoder: DataDecoder = JSONDecoder(), + emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods) -> DecodableResponseSerializer where Self == DecodableResponseSerializer { + DecodableResponseSerializer(dataPreprocessor: dataPreprocessor, + decoder: decoder, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods) + } +} +#endif + +extension DataRequest { + /// Adds a handler using a `DecodableResponseSerializer` to be called once the request has finished. + /// + /// - Parameters: + /// - type: `Decodable` type to decode from response data. + /// - queue: The queue on which the completion handler is dispatched. `.main` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the + /// `completionHandler`. `PassthroughPreprocessor()` by default. + /// - decoder: `DataDecoder` to use to decode the response. `JSONDecoder()` by default. + /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined + /// from the server response, falling back to the default HTTP character set, `ISO-8859-1`. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// - completionHandler: A closure to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func responseDecodable(of type: T.Type = T.self, + queue: DispatchQueue = .main, + dataPreprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, + decoder: DataDecoder = JSONDecoder(), + emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods, + completionHandler: @escaping (AFDataResponse) -> Void) -> Self { + response(queue: queue, + responseSerializer: DecodableResponseSerializer(dataPreprocessor: dataPreprocessor, + decoder: decoder, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + completionHandler: completionHandler) + } +} + +extension DownloadRequest { + /// Adds a handler using a `DecodableResponseSerializer` to be called once the request has finished. + /// + /// - Parameters: + /// - type: `Decodable` type to decode from response data. + /// - queue: The queue on which the completion handler is dispatched. `.main` by default. + /// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the + /// `completionHandler`. `PassthroughPreprocessor()` by default. + /// - decoder: `DataDecoder` to use to decode the response. `JSONDecoder()` by default. + /// - encoding: The string encoding. Defaults to `nil`, in which case the encoding will be determined + /// from the server response, falling back to the default HTTP character set, `ISO-8859-1`. + /// - emptyResponseCodes: HTTP status codes for which empty responses are always valid. `[204, 205]` by default. + /// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default. + /// - completionHandler: A closure to be executed once the request has finished. + /// + /// - Returns: The request. + @discardableResult + public func responseDecodable(of type: T.Type = T.self, + queue: DispatchQueue = .main, + dataPreprocessor: DataPreprocessor = DecodableResponseSerializer.defaultDataPreprocessor, + decoder: DataDecoder = JSONDecoder(), + emptyResponseCodes: Set = DecodableResponseSerializer.defaultEmptyResponseCodes, + emptyRequestMethods: Set = DecodableResponseSerializer.defaultEmptyRequestMethods, + completionHandler: @escaping (AFDownloadResponse) -> Void) -> Self { + response(queue: queue, + responseSerializer: DecodableResponseSerializer(dataPreprocessor: dataPreprocessor, + decoder: decoder, + emptyResponseCodes: emptyResponseCodes, + emptyRequestMethods: emptyRequestMethods), + completionHandler: completionHandler) + } +} + +// MARK: - DataStreamRequest + +/// A type which can serialize incoming `Data`. +public protocol DataStreamSerializer { + /// Type produced from the serialized `Data`. + associatedtype SerializedObject + + /// Serializes incoming `Data` into a `SerializedObject` value. + /// + /// - Parameter data: `Data` to be serialized. + /// + /// - Throws: Any error produced during serialization. + func serialize(_ data: Data) throws -> SerializedObject +} + +/// `DataStreamSerializer` which uses the provided `DataPreprocessor` and `DataDecoder` to serialize the incoming `Data`. +public struct DecodableStreamSerializer: DataStreamSerializer { + /// `DataDecoder` used to decode incoming `Data`. + public let decoder: DataDecoder + /// `DataPreprocessor` incoming `Data` is passed through before being passed to the `DataDecoder`. + public let dataPreprocessor: DataPreprocessor + + /// Creates an instance with the provided `DataDecoder` and `DataPreprocessor`. + /// - Parameters: + /// - decoder: ` DataDecoder` used to decode incoming `Data`. `JSONDecoder()` by default. + /// - dataPreprocessor: `DataPreprocessor` used to process incoming `Data` before it's passed through the + /// `decoder`. `PassthroughPreprocessor()` by default. + public init(decoder: DataDecoder = JSONDecoder(), dataPreprocessor: DataPreprocessor = PassthroughPreprocessor()) { + self.decoder = decoder + self.dataPreprocessor = dataPreprocessor + } + + public func serialize(_ data: Data) throws -> T { + let processedData = try dataPreprocessor.preprocess(data) + do { + return try decoder.decode(T.self, from: processedData) + } catch { + throw AFError.responseSerializationFailed(reason: .decodingFailed(error: error)) + } + } +} + +/// `DataStreamSerializer` which performs no serialization on incoming `Data`. +public struct PassthroughStreamSerializer: DataStreamSerializer { + /// Creates an instance. + public init() {} + + public func serialize(_ data: Data) throws -> Data { data } +} + +/// `DataStreamSerializer` which serializes incoming stream `Data` into `UTF8`-decoded `String` values. +public struct StringStreamSerializer: DataStreamSerializer { + /// Creates an instance. + public init() {} + + public func serialize(_ data: Data) throws -> String { + String(decoding: data, as: UTF8.self) + } +} + +#if swift(>=5.5) +extension DataStreamSerializer { + /// Creates a `DecodableStreamSerializer` instance with the provided `DataDecoder` and `DataPreprocessor`. + /// + /// - Parameters: + /// - type: `Decodable` type to decode from stream data. + /// - decoder: ` DataDecoder` used to decode incoming `Data`. `JSONDecoder()` by default. + /// - dataPreprocessor: `DataPreprocessor` used to process incoming `Data` before it's passed through the + /// `decoder`. `PassthroughPreprocessor()` by default. + public static func decodable(of type: T.Type, + decoder: DataDecoder = JSONDecoder(), + dataPreprocessor: DataPreprocessor = PassthroughPreprocessor()) -> Self where Self == DecodableStreamSerializer { + DecodableStreamSerializer(decoder: decoder, dataPreprocessor: dataPreprocessor) + } +} + +extension DataStreamSerializer where Self == PassthroughStreamSerializer { + /// Provides a `PassthroughStreamSerializer` instance. + public static var passthrough: PassthroughStreamSerializer { PassthroughStreamSerializer() } +} + +extension DataStreamSerializer where Self == StringStreamSerializer { + /// Provides a `StringStreamSerializer` instance. + public static var string: StringStreamSerializer { StringStreamSerializer() } +} +#endif + +extension DataStreamRequest { + /// Adds a `StreamHandler` which performs no parsing on incoming `Data`. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which to perform `StreamHandler` closure. + /// - stream: `StreamHandler` closure called as `Data` is received. May be called multiple times. + /// + /// - Returns: The `DataStreamRequest`. + @discardableResult + public func responseStream(on queue: DispatchQueue = .main, stream: @escaping Handler) -> Self { + let parser = { [unowned self] (data: Data) in + queue.async { + self.capturingError { + try stream(.init(event: .stream(.success(data)), token: .init(self))) + } + + self.updateAndCompleteIfPossible() + } + } + + $streamMutableState.write { $0.streams.append(parser) } + appendStreamCompletion(on: queue, stream: stream) + + return self + } + + /// Adds a `StreamHandler` which uses the provided `DataStreamSerializer` to process incoming `Data`. + /// + /// - Parameters: + /// - serializer: `DataStreamSerializer` used to process incoming `Data`. Its work is done on the `serializationQueue`. + /// - queue: `DispatchQueue` on which to perform `StreamHandler` closure. + /// - stream: `StreamHandler` closure called as `Data` is received. May be called multiple times. + /// + /// - Returns: The `DataStreamRequest`. + @discardableResult + public func responseStream(using serializer: Serializer, + on queue: DispatchQueue = .main, + stream: @escaping Handler) -> Self { + let parser = { [unowned self] (data: Data) in + self.serializationQueue.async { + // Start work on serialization queue. + let result = Result { try serializer.serialize(data) } + .mapError { $0.asAFError(or: .responseSerializationFailed(reason: .customSerializationFailed(error: $0))) } + // End work on serialization queue. + self.underlyingQueue.async { + self.eventMonitor?.request(self, didParseStream: result) + + if result.isFailure, self.automaticallyCancelOnStreamError { + self.cancel() + } + + queue.async { + self.capturingError { + try stream(.init(event: .stream(result), token: .init(self))) + } + + self.updateAndCompleteIfPossible() + } + } + } + } + + $streamMutableState.write { $0.streams.append(parser) } + appendStreamCompletion(on: queue, stream: stream) + + return self + } + + /// Adds a `StreamHandler` which parses incoming `Data` as a UTF8 `String`. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which to perform `StreamHandler` closure. + /// - stream: `StreamHandler` closure called as `Data` is received. May be called multiple times. + /// + /// - Returns: The `DataStreamRequest`. + @discardableResult + public func responseStreamString(on queue: DispatchQueue = .main, + stream: @escaping Handler) -> Self { + let parser = { [unowned self] (data: Data) in + self.serializationQueue.async { + // Start work on serialization queue. + let string = String(decoding: data, as: UTF8.self) + // End work on serialization queue. + self.underlyingQueue.async { + self.eventMonitor?.request(self, didParseStream: .success(string)) + + queue.async { + self.capturingError { + try stream(.init(event: .stream(.success(string)), token: .init(self))) + } + + self.updateAndCompleteIfPossible() + } + } + } + } + + $streamMutableState.write { $0.streams.append(parser) } + appendStreamCompletion(on: queue, stream: stream) + + return self + } + + private func updateAndCompleteIfPossible() { + $streamMutableState.write { state in + state.numberOfExecutingStreams -= 1 + + guard state.numberOfExecutingStreams == 0, !state.enqueuedCompletionEvents.isEmpty else { return } + + let completionEvents = state.enqueuedCompletionEvents + self.underlyingQueue.async { completionEvents.forEach { $0() } } + state.enqueuedCompletionEvents.removeAll() + } + } + + /// Adds a `StreamHandler` which parses incoming `Data` using the provided `DataDecoder`. + /// + /// - Parameters: + /// - type: `Decodable` type to parse incoming `Data` into. + /// - queue: `DispatchQueue` on which to perform `StreamHandler` closure. + /// - decoder: `DataDecoder` used to decode the incoming `Data`. + /// - preprocessor: `DataPreprocessor` used to process the incoming `Data` before it's passed to the `decoder`. + /// - stream: `StreamHandler` closure called as `Data` is received. May be called multiple times. + /// + /// - Returns: The `DataStreamRequest`. + @discardableResult + public func responseStreamDecodable(of type: T.Type = T.self, + on queue: DispatchQueue = .main, + using decoder: DataDecoder = JSONDecoder(), + preprocessor: DataPreprocessor = PassthroughPreprocessor(), + stream: @escaping Handler) -> Self { + responseStream(using: DecodableStreamSerializer(decoder: decoder, dataPreprocessor: preprocessor), + stream: stream) + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/Result+Alamofire.swift b/Instagram-Clone/Pods/Alamofire/Source/Result+Alamofire.swift new file mode 100644 index 0000000..39ac286 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/Result+Alamofire.swift @@ -0,0 +1,120 @@ +// +// Result+Alamofire.swift +// +// Copyright (c) 2019 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 + +/// Default type of `Result` returned by Alamofire, with an `AFError` `Failure` type. +public typealias AFResult = Result + +// MARK: - Internal APIs + +extension Result { + /// Returns whether the instance is `.success`. + var isSuccess: Bool { + guard case .success = self else { return false } + return true + } + + /// Returns whether the instance is `.failure`. + var isFailure: Bool { + !isSuccess + } + + /// Returns the associated value if the result is a success, `nil` otherwise. + var success: Success? { + guard case let .success(value) = self else { return nil } + return value + } + + /// Returns the associated error value if the result is a failure, `nil` otherwise. + var failure: Failure? { + guard case let .failure(error) = self else { return nil } + return error + } + + /// Initializes a `Result` from value or error. Returns `.failure` if the error is non-nil, `.success` otherwise. + /// + /// - Parameters: + /// - value: A value. + /// - error: An `Error`. + init(value: Success, error: Failure?) { + if let error = error { + self = .failure(error) + } else { + self = .success(value) + } + } + + /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter. + /// + /// Use the `tryMap` method with a closure that may throw an error. For example: + /// + /// let possibleData: Result = .success(Data(...)) + /// let possibleObject = possibleData.tryMap { + /// 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. + func tryMap(_ transform: (Success) throws -> NewSuccess) -> Result { + switch self { + case let .success(value): + do { + return try .success(transform(value)) + } catch { + return .failure(error) + } + case let .failure(error): + return .failure(error) + } + } + + /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter. + /// + /// Use the `tryMapError` function with a closure that may throw an error. For example: + /// + /// let possibleData: Result = .success(Data(...)) + /// let possibleObject = possibleData.tryMapError { + /// 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 success. + func tryMapError(_ transform: (Failure) throws -> NewFailure) -> Result { + switch self { + case let .failure(error): + do { + return try .failure(transform(error)) + } catch { + return .failure(error) + } + case let .success(value): + return .success(value) + } + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/RetryPolicy.swift b/Instagram-Clone/Pods/Alamofire/Source/RetryPolicy.swift new file mode 100644 index 0000000..f6fd8d3 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/RetryPolicy.swift @@ -0,0 +1,434 @@ +// +// RetryPolicy.swift +// +// Copyright (c) 2019-2020 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 retry policy that retries requests using an exponential backoff for allowed HTTP methods and HTTP status codes +/// as well as certain types of networking errors. +open class RetryPolicy: RequestInterceptor { + /// The default retry limit for retry policies. + public static let defaultRetryLimit: UInt = 2 + + /// The default exponential backoff base for retry policies (must be a minimum of 2). + public static let defaultExponentialBackoffBase: UInt = 2 + + /// The default exponential backoff scale for retry policies. + public static let defaultExponentialBackoffScale: Double = 0.5 + + /// The default HTTP methods to retry. + /// See [RFC 2616 - Section 9.1.2](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) for more information. + public static let defaultRetryableHTTPMethods: Set = [.delete, // [Delete](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.7) - not always idempotent + .get, // [GET](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3) - generally idempotent + .head, // [HEAD](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4) - generally idempotent + .options, // [OPTIONS](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.2) - inherently idempotent + .put, // [PUT](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6) - not always idempotent + .trace // [TRACE](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.8) - inherently idempotent + ] + + /// The default HTTP status codes to retry. + /// See [RFC 2616 - Section 10](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10) for more information. + public static let defaultRetryableHTTPStatusCodes: Set = [408, // [Request Timeout](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.9) + 500, // [Internal Server Error](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1) + 502, // [Bad Gateway](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.3) + 503, // [Service Unavailable](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.4) + 504 // [Gateway Timeout](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.5) + ] + + /// The default URL error codes to retry. + public static let defaultRetryableURLErrorCodes: Set = [// [Security] App Transport Security disallowed a connection because there is no secure network connection. + // - [Disabled] ATS settings do not change at runtime. + // .appTransportSecurityRequiresSecureConnection, + + // [System] An app or app extension attempted to connect to a background session that is already connected to a + // process. + // - [Enabled] The other process could release the background session. + .backgroundSessionInUseByAnotherProcess, + + // [System] The shared container identifier of the URL session configuration is needed but has not been set. + // - [Disabled] Cannot change at runtime. + // .backgroundSessionRequiresSharedContainer, + + // [System] The app is suspended or exits while a background data task is processing. + // - [Enabled] App can be foregrounded or launched to recover. + .backgroundSessionWasDisconnected, + + // [Network] The URL Loading system received bad data from the server. + // - [Enabled] Server could return valid data when retrying. + .badServerResponse, + + // [Resource] A malformed URL prevented a URL request from being initiated. + // - [Disabled] URL was most likely constructed incorrectly. + // .badURL, + + // [System] A connection was attempted while a phone call is active on a network that does not support + // simultaneous phone and data communication (EDGE or GPRS). + // - [Enabled] Phone call could be ended to allow request to recover. + .callIsActive, + + // [Client] An asynchronous load has been canceled. + // - [Disabled] Request was cancelled by the client. + // .cancelled, + + // [File System] A download task couldn’t close the downloaded file on disk. + // - [Disabled] File system error is unlikely to recover with retry. + // .cannotCloseFile, + + // [Network] An attempt to connect to a host failed. + // - [Enabled] Server or DNS lookup could recover during retry. + .cannotConnectToHost, + + // [File System] A download task couldn’t create the downloaded file on disk because of an I/O failure. + // - [Disabled] File system error is unlikely to recover with retry. + // .cannotCreateFile, + + // [Data] Content data received during a connection request had an unknown content encoding. + // - [Disabled] Server is unlikely to modify the content encoding during a retry. + // .cannotDecodeContentData, + + // [Data] Content data received during a connection request could not be decoded for a known content encoding. + // - [Disabled] Server is unlikely to modify the content encoding during a retry. + // .cannotDecodeRawData, + + // [Network] The host name for a URL could not be resolved. + // - [Enabled] Server or DNS lookup could recover during retry. + .cannotFindHost, + + // [Network] A request to load an item only from the cache could not be satisfied. + // - [Enabled] Cache could be populated during a retry. + .cannotLoadFromNetwork, + + // [File System] A download task was unable to move a downloaded file on disk. + // - [Disabled] File system error is unlikely to recover with retry. + // .cannotMoveFile, + + // [File System] A download task was unable to open the downloaded file on disk. + // - [Disabled] File system error is unlikely to recover with retry. + // .cannotOpenFile, + + // [Data] A task could not parse a response. + // - [Disabled] Invalid response is unlikely to recover with retry. + // .cannotParseResponse, + + // [File System] A download task was unable to remove a downloaded file from disk. + // - [Disabled] File system error is unlikely to recover with retry. + // .cannotRemoveFile, + + // [File System] A download task was unable to write to the downloaded file on disk. + // - [Disabled] File system error is unlikely to recover with retry. + // .cannotWriteToFile, + + // [Security] A client certificate was rejected. + // - [Disabled] Client certificate is unlikely to change with retry. + // .clientCertificateRejected, + + // [Security] A client certificate was required to authenticate an SSL connection during a request. + // - [Disabled] Client certificate is unlikely to be provided with retry. + // .clientCertificateRequired, + + // [Data] The length of the resource data exceeds the maximum allowed. + // - [Disabled] Resource will likely still exceed the length maximum on retry. + // .dataLengthExceedsMaximum, + + // [System] The cellular network disallowed a connection. + // - [Enabled] WiFi connection could be established during retry. + .dataNotAllowed, + + // [Network] The host address could not be found via DNS lookup. + // - [Enabled] DNS lookup could succeed during retry. + .dnsLookupFailed, + + // [Data] A download task failed to decode an encoded file during the download. + // - [Enabled] Server could correct the decoding issue with retry. + .downloadDecodingFailedMidStream, + + // [Data] A download task failed to decode an encoded file after downloading. + // - [Enabled] Server could correct the decoding issue with retry. + .downloadDecodingFailedToComplete, + + // [File System] A file does not exist. + // - [Disabled] File system error is unlikely to recover with retry. + // .fileDoesNotExist, + + // [File System] A request for an FTP file resulted in the server responding that the file is not a plain file, + // but a directory. + // - [Disabled] FTP directory is not likely to change to a file during a retry. + // .fileIsDirectory, + + // [Network] A redirect loop has been detected or the threshold for number of allowable redirects has been + // exceeded (currently 16). + // - [Disabled] The redirect loop is unlikely to be resolved within the retry window. + // .httpTooManyRedirects, + + // [System] The attempted connection required activating a data context while roaming, but international roaming + // is disabled. + // - [Enabled] WiFi connection could be established during retry. + .internationalRoamingOff, + + // [Connectivity] A client or server connection was severed in the middle of an in-progress load. + // - [Enabled] A network connection could be established during retry. + .networkConnectionLost, + + // [File System] A resource couldn’t be read because of insufficient permissions. + // - [Disabled] Permissions are unlikely to be granted during retry. + // .noPermissionsToReadFile, + + // [Connectivity] A network resource was requested, but an internet connection has not been established and + // cannot be established automatically. + // - [Enabled] A network connection could be established during retry. + .notConnectedToInternet, + + // [Resource] A redirect was specified by way of server response code, but the server did not accompany this + // code with a redirect URL. + // - [Disabled] The redirect URL is unlikely to be supplied during a retry. + // .redirectToNonExistentLocation, + + // [Client] A body stream is needed but the client did not provide one. + // - [Disabled] The client will be unlikely to supply a body stream during retry. + // .requestBodyStreamExhausted, + + // [Resource] A requested resource couldn’t be retrieved. + // - [Disabled] The resource is unlikely to become available during the retry window. + // .resourceUnavailable, + + // [Security] An attempt to establish a secure connection failed for reasons that can’t be expressed more + // specifically. + // - [Enabled] The secure connection could be established during a retry given the lack of specificity + // provided by the error. + .secureConnectionFailed, + + // [Security] A server certificate had a date which indicates it has expired, or is not yet valid. + // - [Enabled] The server certificate could become valid within the retry window. + .serverCertificateHasBadDate, + + // [Security] A server certificate was not signed by any root server. + // - [Disabled] The server certificate is unlikely to change during the retry window. + // .serverCertificateHasUnknownRoot, + + // [Security] A server certificate is not yet valid. + // - [Enabled] The server certificate could become valid within the retry window. + .serverCertificateNotYetValid, + + // [Security] A server certificate was signed by a root server that isn’t trusted. + // - [Disabled] The server certificate is unlikely to become trusted within the retry window. + // .serverCertificateUntrusted, + + // [Network] An asynchronous operation timed out. + // - [Enabled] The request timed out for an unknown reason and should be retried. + .timedOut + + // [System] The URL Loading System encountered an error that it can’t interpret. + // - [Disabled] The error could not be interpreted and is unlikely to be recovered from during a retry. + // .unknown, + + // [Resource] A properly formed URL couldn’t be handled by the framework. + // - [Disabled] The URL is unlikely to change during a retry. + // .unsupportedURL, + + // [Client] Authentication is required to access a resource. + // - [Disabled] The user authentication is unlikely to be provided by retrying. + // .userAuthenticationRequired, + + // [Client] An asynchronous request for authentication has been canceled by the user. + // - [Disabled] The user cancelled authentication and explicitly took action to not retry. + // .userCancelledAuthentication, + + // [Resource] A server reported that a URL has a non-zero content length, but terminated the network connection + // gracefully without sending any data. + // - [Disabled] The server is unlikely to provide data during the retry window. + // .zeroByteResource, + ] + + /// The total number of times the request is allowed to be retried. + public let retryLimit: UInt + + /// The base of the exponential backoff policy (should always be greater than or equal to 2). + public let exponentialBackoffBase: UInt + + /// The scale of the exponential backoff. + public let exponentialBackoffScale: Double + + /// The HTTP methods that are allowed to be retried. + public let retryableHTTPMethods: Set + + /// The HTTP status codes that are automatically retried by the policy. + public let retryableHTTPStatusCodes: Set + + /// The URL error codes that are automatically retried by the policy. + public let retryableURLErrorCodes: Set + + /// Creates a `RetryPolicy` from the specified parameters. + /// + /// - Parameters: + /// - retryLimit: The total number of times the request is allowed to be retried. `2` by default. + /// - exponentialBackoffBase: The base of the exponential backoff policy. `2` by default. + /// - exponentialBackoffScale: The scale of the exponential backoff. `0.5` by default. + /// - retryableHTTPMethods: The HTTP methods that are allowed to be retried. + /// `RetryPolicy.defaultRetryableHTTPMethods` by default. + /// - retryableHTTPStatusCodes: The HTTP status codes that are automatically retried by the policy. + /// `RetryPolicy.defaultRetryableHTTPStatusCodes` by default. + /// - retryableURLErrorCodes: The URL error codes that are automatically retried by the policy. + /// `RetryPolicy.defaultRetryableURLErrorCodes` by default. + public init(retryLimit: UInt = RetryPolicy.defaultRetryLimit, + exponentialBackoffBase: UInt = RetryPolicy.defaultExponentialBackoffBase, + exponentialBackoffScale: Double = RetryPolicy.defaultExponentialBackoffScale, + retryableHTTPMethods: Set = RetryPolicy.defaultRetryableHTTPMethods, + retryableHTTPStatusCodes: Set = RetryPolicy.defaultRetryableHTTPStatusCodes, + retryableURLErrorCodes: Set = RetryPolicy.defaultRetryableURLErrorCodes) { + precondition(exponentialBackoffBase >= 2, "The `exponentialBackoffBase` must be a minimum of 2.") + + self.retryLimit = retryLimit + self.exponentialBackoffBase = exponentialBackoffBase + self.exponentialBackoffScale = exponentialBackoffScale + self.retryableHTTPMethods = retryableHTTPMethods + self.retryableHTTPStatusCodes = retryableHTTPStatusCodes + self.retryableURLErrorCodes = retryableURLErrorCodes + } + + open func retry(_ request: Request, + for session: Session, + dueTo error: Error, + completion: @escaping (RetryResult) -> Void) { + if request.retryCount < retryLimit, shouldRetry(request: request, dueTo: error) { + completion(.retryWithDelay(pow(Double(exponentialBackoffBase), Double(request.retryCount)) * exponentialBackoffScale)) + } else { + completion(.doNotRetry) + } + } + + /// Determines whether or not to retry the provided `Request`. + /// + /// - Parameters: + /// - request: `Request` that failed due to the provided `Error`. + /// - error: `Error` encountered while executing the `Request`. + /// + /// - Returns: `Bool` determining whether or not to retry the `Request`. + open func shouldRetry(request: Request, dueTo error: Error) -> Bool { + guard let httpMethod = request.request?.method, retryableHTTPMethods.contains(httpMethod) else { return false } + + if let statusCode = request.response?.statusCode, retryableHTTPStatusCodes.contains(statusCode) { + return true + } else { + let errorCode = (error as? URLError)?.code + let afErrorCode = (error.asAFError?.underlyingError as? URLError)?.code + + guard let code = errorCode ?? afErrorCode else { return false } + + return retryableURLErrorCodes.contains(code) + } + } +} + +#if swift(>=5.5) +extension RequestInterceptor where Self == RetryPolicy { + /// Provides a default `RetryPolicy` instance. + public static var retryPolicy: RetryPolicy { RetryPolicy() } + + /// Creates an `RetryPolicy` from the specified parameters. + /// + /// - Parameters: + /// - retryLimit: The total number of times the request is allowed to be retried. `2` by default. + /// - exponentialBackoffBase: The base of the exponential backoff policy. `2` by default. + /// - exponentialBackoffScale: The scale of the exponential backoff. `0.5` by default. + /// - retryableHTTPMethods: The HTTP methods that are allowed to be retried. + /// `RetryPolicy.defaultRetryableHTTPMethods` by default. + /// - retryableHTTPStatusCodes: The HTTP status codes that are automatically retried by the policy. + /// `RetryPolicy.defaultRetryableHTTPStatusCodes` by default. + /// - retryableURLErrorCodes: The URL error codes that are automatically retried by the policy. + /// `RetryPolicy.defaultRetryableURLErrorCodes` by default. + /// + /// - Returns: The `RetryPolicy` + public static func retryPolicy(retryLimit: UInt = RetryPolicy.defaultRetryLimit, + exponentialBackoffBase: UInt = RetryPolicy.defaultExponentialBackoffBase, + exponentialBackoffScale: Double = RetryPolicy.defaultExponentialBackoffScale, + retryableHTTPMethods: Set = RetryPolicy.defaultRetryableHTTPMethods, + retryableHTTPStatusCodes: Set = RetryPolicy.defaultRetryableHTTPStatusCodes, + retryableURLErrorCodes: Set = RetryPolicy.defaultRetryableURLErrorCodes) -> RetryPolicy { + RetryPolicy(retryLimit: retryLimit, + exponentialBackoffBase: exponentialBackoffBase, + exponentialBackoffScale: exponentialBackoffScale, + retryableHTTPMethods: retryableHTTPMethods, + retryableHTTPStatusCodes: retryableHTTPStatusCodes, + retryableURLErrorCodes: retryableURLErrorCodes) + } +} +#endif + +// MARK: - + +/// A retry policy that automatically retries idempotent requests for network connection lost errors. For more +/// information about retrying network connection lost errors, please refer to Apple's +/// [technical document](https://developer.apple.com/library/content/qa/qa1941/_index.html). +open class ConnectionLostRetryPolicy: RetryPolicy { + /// Creates a `ConnectionLostRetryPolicy` instance from the specified parameters. + /// + /// - Parameters: + /// - retryLimit: The total number of times the request is allowed to be retried. + /// `RetryPolicy.defaultRetryLimit` by default. + /// - exponentialBackoffBase: The base of the exponential backoff policy. + /// `RetryPolicy.defaultExponentialBackoffBase` by default. + /// - exponentialBackoffScale: The scale of the exponential backoff. + /// `RetryPolicy.defaultExponentialBackoffScale` by default. + /// - retryableHTTPMethods: The idempotent http methods to retry. + /// `RetryPolicy.defaultRetryableHTTPMethods` by default. + public init(retryLimit: UInt = RetryPolicy.defaultRetryLimit, + exponentialBackoffBase: UInt = RetryPolicy.defaultExponentialBackoffBase, + exponentialBackoffScale: Double = RetryPolicy.defaultExponentialBackoffScale, + retryableHTTPMethods: Set = RetryPolicy.defaultRetryableHTTPMethods) { + super.init(retryLimit: retryLimit, + exponentialBackoffBase: exponentialBackoffBase, + exponentialBackoffScale: exponentialBackoffScale, + retryableHTTPMethods: retryableHTTPMethods, + retryableHTTPStatusCodes: [], + retryableURLErrorCodes: [.networkConnectionLost]) + } +} + +#if swift(>=5.5) +extension RequestInterceptor where Self == ConnectionLostRetryPolicy { + /// Provides a default `ConnectionLostRetryPolicy` instance. + public static var connectionLostRetryPolicy: ConnectionLostRetryPolicy { ConnectionLostRetryPolicy() } + + /// Creates a `ConnectionLostRetryPolicy` instance from the specified parameters. + /// + /// - Parameters: + /// - retryLimit: The total number of times the request is allowed to be retried. + /// `RetryPolicy.defaultRetryLimit` by default. + /// - exponentialBackoffBase: The base of the exponential backoff policy. + /// `RetryPolicy.defaultExponentialBackoffBase` by default. + /// - exponentialBackoffScale: The scale of the exponential backoff. + /// `RetryPolicy.defaultExponentialBackoffScale` by default. + /// - retryableHTTPMethods: The idempotent http methods to retry. + /// + /// - Returns: The `ConnectionLostRetryPolicy`. + public static func connectionLostRetryPolicy(retryLimit: UInt = RetryPolicy.defaultRetryLimit, + exponentialBackoffBase: UInt = RetryPolicy.defaultExponentialBackoffBase, + exponentialBackoffScale: Double = RetryPolicy.defaultExponentialBackoffScale, + retryableHTTPMethods: Set = RetryPolicy.defaultRetryableHTTPMethods) -> ConnectionLostRetryPolicy { + ConnectionLostRetryPolicy(retryLimit: retryLimit, + exponentialBackoffBase: exponentialBackoffBase, + exponentialBackoffScale: exponentialBackoffScale, + retryableHTTPMethods: retryableHTTPMethods) + } +} +#endif diff --git a/Instagram-Clone/Pods/Alamofire/Source/ServerTrustEvaluation.swift b/Instagram-Clone/Pods/Alamofire/Source/ServerTrustEvaluation.swift new file mode 100644 index 0000000..d63a63d --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/ServerTrustEvaluation.swift @@ -0,0 +1,719 @@ +// +// ServerTrustPolicy.swift +// +// Copyright (c) 2014-2016 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 `ServerTrustEvaluating` values to given hosts. +open class ServerTrustManager { + /// Determines whether all hosts for this `ServerTrustManager` must be evaluated. `true` by default. + public let allHostsMustBeEvaluated: Bool + + /// The dictionary of policies mapped to a particular host. + public let evaluators: [String: ServerTrustEvaluating] + + /// Initializes the `ServerTrustManager` instance with the given evaluators. + /// + /// Since different servers and web services can have different leaf certificates, intermediate and even root + /// certificates, 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. + /// + /// - Parameters: + /// - allHostsMustBeEvaluated: The value determining whether all hosts for this instance must be evaluated. `true` + /// by default. + /// - evaluators: A dictionary of evaluators mapped to hosts. + public init(allHostsMustBeEvaluated: Bool = true, evaluators: [String: ServerTrustEvaluating]) { + self.allHostsMustBeEvaluated = allHostsMustBeEvaluated + self.evaluators = evaluators + } + + #if !(os(Linux) || os(Windows)) + /// Returns the `ServerTrustEvaluating` value for the given host, if one is set. + /// + /// 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 `ServerTrustEvaluating` value for the given host if found, `nil` otherwise. + /// - Throws: `AFError.serverTrustEvaluationFailed` if `allHostsMustBeEvaluated` is `true` and no matching + /// evaluators are found. + open func serverTrustEvaluator(forHost host: String) throws -> ServerTrustEvaluating? { + guard let evaluator = evaluators[host] else { + if allHostsMustBeEvaluated { + throw AFError.serverTrustEvaluationFailed(reason: .noRequiredEvaluator(host: host)) + } + + return nil + } + + return evaluator + } + #endif +} + +/// A protocol describing the API used to evaluate server trusts. +public protocol ServerTrustEvaluating { + #if os(Linux) || os(Windows) + // Implement this once Linux/Windows has API for evaluating server trusts. + #else + /// Evaluates the given `SecTrust` value for the given `host`. + /// + /// - Parameters: + /// - trust: The `SecTrust` value to evaluate. + /// - host: The host for which to evaluate the `SecTrust` value. + /// + /// - Returns: A `Bool` indicating whether the evaluator considers the `SecTrust` value valid for `host`. + func evaluate(_ trust: SecTrust, forHost host: String) throws + #endif +} + +// MARK: - Server Trust Evaluators + +#if !(os(Linux) || os(Windows)) +/// An evaluator which 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. +public final class DefaultTrustEvaluator: ServerTrustEvaluating { + private let validateHost: Bool + + /// Creates a `DefaultTrustEvaluator`. + /// + /// - Parameter validateHost: Determines whether or not the evaluator should validate the host. `true` by default. + public init(validateHost: Bool = true) { + self.validateHost = validateHost + } + + public func evaluate(_ trust: SecTrust, forHost host: String) throws { + if validateHost { + try trust.af.performValidation(forHost: host) + } + + try trust.af.performDefaultValidation(forHost: host) + } +} + +/// An evaluator which 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. +public final class RevocationTrustEvaluator: ServerTrustEvaluating { + /// Represents the options to be use when evaluating the status of a certificate. + /// Only Revocation Policy Constants are valid, and can be found in [Apple's documentation](https://developer.apple.com/documentation/security/certificate_key_and_trust_services/policies/1563600-revocation_policy_constants). + public struct Options: OptionSet { + /// Perform revocation checking using the CRL (Certification Revocation List) method. + public static let crl = Options(rawValue: kSecRevocationCRLMethod) + /// Consult only locally cached replies; do not use network access. + public static let networkAccessDisabled = Options(rawValue: kSecRevocationNetworkAccessDisabled) + /// Perform revocation checking using OCSP (Online Certificate Status Protocol). + public static let ocsp = Options(rawValue: kSecRevocationOCSPMethod) + /// Prefer CRL revocation checking over OCSP; by default, OCSP is preferred. + public static let preferCRL = Options(rawValue: kSecRevocationPreferCRL) + /// Require a positive response to pass the policy. If the flag is not set, revocation checking is done on a + /// "best attempt" basis, where failure to reach the server is not considered fatal. + public static let requirePositiveResponse = Options(rawValue: kSecRevocationRequirePositiveResponse) + /// Perform either OCSP or CRL checking. The checking is performed according to the method(s) specified in the + /// certificate and the value of `preferCRL`. + public static let any = Options(rawValue: kSecRevocationUseAnyAvailableMethod) + + /// The raw value of the option. + public let rawValue: CFOptionFlags + + /// Creates an `Options` value with the given `CFOptionFlags`. + /// + /// - Parameter rawValue: The `CFOptionFlags` value to initialize with. + public init(rawValue: CFOptionFlags) { + self.rawValue = rawValue + } + } + + private let performDefaultValidation: Bool + private let validateHost: Bool + private let options: Options + + /// Creates a `RevocationTrustEvaluator` using the provided parameters. + /// + /// - Note: Default and host validation will fail when using this evaluator with self-signed certificates. Use + /// `PinnedCertificatesTrustEvaluator` if you need to use self-signed certificates. + /// + /// - Parameters: + /// - performDefaultValidation: Determines whether default validation should be performed in addition to + /// evaluating the pinned certificates. `true` by default. + /// - validateHost: Determines whether or not the evaluator should validate the host, in addition to + /// performing the default evaluation, even if `performDefaultValidation` is `false`. + /// `true` by default. + /// - options: The `Options` to use to check the revocation status of the certificate. `.any` by + /// default. + public init(performDefaultValidation: Bool = true, validateHost: Bool = true, options: Options = .any) { + self.performDefaultValidation = performDefaultValidation + self.validateHost = validateHost + self.options = options + } + + public func evaluate(_ trust: SecTrust, forHost host: String) throws { + if performDefaultValidation { + try trust.af.performDefaultValidation(forHost: host) + } + + if validateHost { + try trust.af.performValidation(forHost: host) + } + + if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, *) { + try trust.af.evaluate(afterApplying: SecPolicy.af.revocation(options: options)) + } else { + try trust.af.validate(policy: SecPolicy.af.revocation(options: options)) { status, result in + AFError.serverTrustEvaluationFailed(reason: .revocationCheckFailed(output: .init(host, trust, status, result), options: options)) + } + } + } +} + +#if swift(>=5.5) +extension ServerTrustEvaluating where Self == RevocationTrustEvaluator { + /// Provides a default `RevocationTrustEvaluator` instance. + public static var revocationChecking: RevocationTrustEvaluator { RevocationTrustEvaluator() } + + /// Creates a `RevocationTrustEvaluator` using the provided parameters. + /// + /// - Note: Default and host validation will fail when using this evaluator with self-signed certificates. Use + /// `PinnedCertificatesTrustEvaluator` if you need to use self-signed certificates. + /// + /// - Parameters: + /// - performDefaultValidation: Determines whether default validation should be performed in addition to + /// evaluating the pinned certificates. `true` by default. + /// - validateHost: Determines whether or not the evaluator should validate the host, in addition + /// to performing the default evaluation, even if `performDefaultValidation` is + /// `false`. `true` by default. + /// - options: The `Options` to use to check the revocation status of the certificate. `.any` + /// by default. + /// - Returns: The `RevocationTrustEvaluator`. + public static func revocationChecking(performDefaultValidation: Bool = true, + validateHost: Bool = true, + options: RevocationTrustEvaluator.Options = .any) -> RevocationTrustEvaluator { + RevocationTrustEvaluator(performDefaultValidation: performDefaultValidation, + validateHost: validateHost, + options: options) + } +} +#endif + +/// 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. +public final class PinnedCertificatesTrustEvaluator: ServerTrustEvaluating { + private let certificates: [SecCertificate] + private let acceptSelfSignedCertificates: Bool + private let performDefaultValidation: Bool + private let validateHost: Bool + + /// Creates a `PinnedCertificatesTrustEvaluator` from the provided parameters. + /// + /// - Parameters: + /// - certificates: The certificates to use to evaluate the trust. All `cer`, `crt`, and `der` + /// certificates in `Bundle.main` by default. + /// - acceptSelfSignedCertificates: Adds the provided certificates as anchors for the trust evaluation, allowing + /// self-signed certificates to pass. `false` by default. THIS SETTING SHOULD BE + /// FALSE IN PRODUCTION! + /// - performDefaultValidation: Determines whether default validation should be performed in addition to + /// evaluating the pinned certificates. `true` by default. + /// - validateHost: Determines whether or not the evaluator should validate the host, in addition + /// to performing the default evaluation, even if `performDefaultValidation` is + /// `false`. `true` by default. + public init(certificates: [SecCertificate] = Bundle.main.af.certificates, + acceptSelfSignedCertificates: Bool = false, + performDefaultValidation: Bool = true, + validateHost: Bool = true) { + self.certificates = certificates + self.acceptSelfSignedCertificates = acceptSelfSignedCertificates + self.performDefaultValidation = performDefaultValidation + self.validateHost = validateHost + } + + public func evaluate(_ trust: SecTrust, forHost host: String) throws { + guard !certificates.isEmpty else { + throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound) + } + + if acceptSelfSignedCertificates { + try trust.af.setAnchorCertificates(certificates) + } + + if performDefaultValidation { + try trust.af.performDefaultValidation(forHost: host) + } + + if validateHost { + try trust.af.performValidation(forHost: host) + } + + let serverCertificatesData = Set(trust.af.certificateData) + let pinnedCertificatesData = Set(certificates.af.data) + let pinnedCertificatesInServerData = !serverCertificatesData.isDisjoint(with: pinnedCertificatesData) + if !pinnedCertificatesInServerData { + throw AFError.serverTrustEvaluationFailed(reason: .certificatePinningFailed(host: host, + trust: trust, + pinnedCertificates: certificates, + serverCertificates: trust.af.certificates)) + } + } +} + +#if swift(>=5.5) +extension ServerTrustEvaluating where Self == PinnedCertificatesTrustEvaluator { + /// Provides a default `PinnedCertificatesTrustEvaluator` instance. + public static var pinnedCertificates: PinnedCertificatesTrustEvaluator { PinnedCertificatesTrustEvaluator() } + + /// Creates a `PinnedCertificatesTrustEvaluator` using the provided parameters. + /// + /// - Parameters: + /// - certificates: The certificates to use to evaluate the trust. All `cer`, `crt`, and `der` + /// certificates in `Bundle.main` by default. + /// - acceptSelfSignedCertificates: Adds the provided certificates as anchors for the trust evaluation, allowing + /// self-signed certificates to pass. `false` by default. THIS SETTING SHOULD BE + /// FALSE IN PRODUCTION! + /// - performDefaultValidation: Determines whether default validation should be performed in addition to + /// evaluating the pinned certificates. `true` by default. + /// - validateHost: Determines whether or not the evaluator should validate the host, in addition + /// to performing the default evaluation, even if `performDefaultValidation` is + /// `false`. `true` by default. + public static func pinnedCertificates(certificates: [SecCertificate] = Bundle.main.af.certificates, + acceptSelfSignedCertificates: Bool = false, + performDefaultValidation: Bool = true, + validateHost: Bool = true) -> PinnedCertificatesTrustEvaluator { + PinnedCertificatesTrustEvaluator(certificates: certificates, + acceptSelfSignedCertificates: acceptSelfSignedCertificates, + performDefaultValidation: performDefaultValidation, + validateHost: validateHost) + } +} +#endif + +/// 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. +public final class PublicKeysTrustEvaluator: ServerTrustEvaluating { + private let keys: [SecKey] + private let performDefaultValidation: Bool + private let validateHost: Bool + + /// Creates a `PublicKeysTrustEvaluator` from the provided parameters. + /// + /// - Note: Default and host validation will fail when using this evaluator with self-signed certificates. Use + /// `PinnedCertificatesTrustEvaluator` if you need to use self-signed certificates. + /// + /// - Parameters: + /// - keys: The `SecKey`s to use to validate public keys. Defaults to the public keys of all + /// certificates included in the main bundle. + /// - performDefaultValidation: Determines whether default validation should be performed in addition to + /// evaluating the pinned certificates. `true` by default. + /// - validateHost: Determines whether or not the evaluator should validate the host, in addition to + /// performing the default evaluation, even if `performDefaultValidation` is `false`. + /// `true` by default. + public init(keys: [SecKey] = Bundle.main.af.publicKeys, + performDefaultValidation: Bool = true, + validateHost: Bool = true) { + self.keys = keys + self.performDefaultValidation = performDefaultValidation + self.validateHost = validateHost + } + + public func evaluate(_ trust: SecTrust, forHost host: String) throws { + guard !keys.isEmpty else { + throw AFError.serverTrustEvaluationFailed(reason: .noPublicKeysFound) + } + + if performDefaultValidation { + try trust.af.performDefaultValidation(forHost: host) + } + + if validateHost { + try trust.af.performValidation(forHost: host) + } + + let pinnedKeysInServerKeys: Bool = { + for serverPublicKey in trust.af.publicKeys { + for pinnedPublicKey in keys { + if serverPublicKey == pinnedPublicKey { + return true + } + } + } + return false + }() + + if !pinnedKeysInServerKeys { + throw AFError.serverTrustEvaluationFailed(reason: .publicKeyPinningFailed(host: host, + trust: trust, + pinnedKeys: keys, + serverKeys: trust.af.publicKeys)) + } + } +} + +#if swift(>=5.5) +extension ServerTrustEvaluating where Self == PublicKeysTrustEvaluator { + /// Provides a default `PublicKeysTrustEvaluator` instance. + public static var publicKeys: PublicKeysTrustEvaluator { PublicKeysTrustEvaluator() } + + /// Creates a `PublicKeysTrustEvaluator` from the provided parameters. + /// + /// - Note: Default and host validation will fail when using this evaluator with self-signed certificates. Use + /// `PinnedCertificatesTrustEvaluator` if you need to use self-signed certificates. + /// + /// - Parameters: + /// - keys: The `SecKey`s to use to validate public keys. Defaults to the public keys of all + /// certificates included in the main bundle. + /// - performDefaultValidation: Determines whether default validation should be performed in addition to + /// evaluating the pinned certificates. `true` by default. + /// - validateHost: Determines whether or not the evaluator should validate the host, in addition to + /// performing the default evaluation, even if `performDefaultValidation` is `false`. + /// `true` by default. + public static func publicKeys(keys: [SecKey] = Bundle.main.af.publicKeys, + performDefaultValidation: Bool = true, + validateHost: Bool = true) -> PublicKeysTrustEvaluator { + PublicKeysTrustEvaluator(keys: keys, performDefaultValidation: performDefaultValidation, validateHost: validateHost) + } +} +#endif + +/// Uses the provided evaluators to validate the server trust. The trust is only considered valid if all of the +/// evaluators consider it valid. +public final class CompositeTrustEvaluator: ServerTrustEvaluating { + private let evaluators: [ServerTrustEvaluating] + + /// Creates a `CompositeTrustEvaluator` from the provided evaluators. + /// + /// - Parameter evaluators: The `ServerTrustEvaluating` values used to evaluate the server trust. + public init(evaluators: [ServerTrustEvaluating]) { + self.evaluators = evaluators + } + + public func evaluate(_ trust: SecTrust, forHost host: String) throws { + try evaluators.evaluate(trust, forHost: host) + } +} + +#if swift(>=5.5) +extension ServerTrustEvaluating where Self == CompositeTrustEvaluator { + /// Creates a `CompositeTrustEvaluator` from the provided evaluators. + /// + /// - Parameter evaluators: The `ServerTrustEvaluating` values used to evaluate the server trust. + public static func composite(evaluators: [ServerTrustEvaluating]) -> CompositeTrustEvaluator { + CompositeTrustEvaluator(evaluators: evaluators) + } +} +#endif + +/// Disables all evaluation which in turn will always consider any server trust as valid. +/// +/// - Note: Instead of disabling server trust evaluation, it's a better idea to configure systems to properly trust test +/// certificates, as outlined in [this Apple tech note](https://developer.apple.com/library/archive/qa/qa1948/_index.html). +/// +/// **THIS EVALUATOR SHOULD NEVER BE USED IN PRODUCTION!** +@available(*, deprecated, renamed: "DisabledTrustEvaluator", message: "DisabledEvaluator has been renamed DisabledTrustEvaluator.") +public typealias DisabledEvaluator = DisabledTrustEvaluator + +/// Disables all evaluation which in turn will always consider any server trust as valid. +/// +/// +/// - Note: Instead of disabling server trust evaluation, it's a better idea to configure systems to properly trust test +/// certificates, as outlined in [this Apple tech note](https://developer.apple.com/library/archive/qa/qa1948/_index.html). +/// +/// **THIS EVALUATOR SHOULD NEVER BE USED IN PRODUCTION!** +public final class DisabledTrustEvaluator: ServerTrustEvaluating { + /// Creates an instance. + public init() {} + + public func evaluate(_ trust: SecTrust, forHost host: String) throws {} +} + +// MARK: - Extensions + +extension Array where Element == ServerTrustEvaluating { + #if os(Linux) || os(Windows) + // Add this same convenience method for Linux/Windows. + #else + /// Evaluates the given `SecTrust` value for the given `host`. + /// + /// - Parameters: + /// - trust: The `SecTrust` value to evaluate. + /// - host: The host for which to evaluate the `SecTrust` value. + /// + /// - Returns: Whether or not the evaluator considers the `SecTrust` value valid for `host`. + public func evaluate(_ trust: SecTrust, forHost host: String) throws { + for evaluator in self { + try evaluator.evaluate(trust, forHost: host) + } + } + #endif +} + +extension Bundle: AlamofireExtended {} +extension AlamofireExtension where ExtendedType: Bundle { + /// Returns all valid `cer`, `crt`, and `der` certificates in the bundle. + public var certificates: [SecCertificate] { + paths(forResourcesOfTypes: [".cer", ".CER", ".crt", ".CRT", ".der", ".DER"]).compactMap { path in + guard + let certificateData = try? Data(contentsOf: URL(fileURLWithPath: path)) as CFData, + let certificate = SecCertificateCreateWithData(nil, certificateData) else { return nil } + + return certificate + } + } + + /// Returns all public keys for the valid certificates in the bundle. + public var publicKeys: [SecKey] { + certificates.af.publicKeys + } + + /// Returns all pathnames for the resources identified by the provided file extensions. + /// + /// - Parameter types: The filename extensions locate. + /// + /// - Returns: All pathnames for the given filename extensions. + public func paths(forResourcesOfTypes types: [String]) -> [String] { + Array(Set(types.flatMap { type.paths(forResourcesOfType: $0, inDirectory: nil) })) + } +} + +extension SecTrust: AlamofireExtended {} +extension AlamofireExtension where ExtendedType == SecTrust { + /// Evaluates `self` after applying the `SecPolicy` value provided. + /// + /// - Parameter policy: The `SecPolicy` to apply to `self` before evaluation. + /// + /// - Throws: Any `Error` from applying the `SecPolicy` or from evaluation. + @available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, *) + public func evaluate(afterApplying policy: SecPolicy) throws { + try apply(policy: policy).af.evaluate() + } + + /// Attempts to validate `self` using the `SecPolicy` provided and transforming any error produced using the closure passed. + /// + /// - Parameters: + /// - policy: The `SecPolicy` used to evaluate `self`. + /// - errorProducer: The closure used transform the failed `OSStatus` and `SecTrustResultType`. + /// - Throws: Any `Error` from applying the `policy`, or the result of `errorProducer` if validation fails. + @available(iOS, introduced: 10, deprecated: 12, renamed: "evaluate(afterApplying:)") + @available(macOS, introduced: 10.12, deprecated: 10.14, renamed: "evaluate(afterApplying:)") + @available(tvOS, introduced: 10, deprecated: 12, renamed: "evaluate(afterApplying:)") + @available(watchOS, introduced: 3, deprecated: 5, renamed: "evaluate(afterApplying:)") + public func validate(policy: SecPolicy, errorProducer: (_ status: OSStatus, _ result: SecTrustResultType) -> Error) throws { + try apply(policy: policy).af.validate(errorProducer: errorProducer) + } + + /// Applies a `SecPolicy` to `self`, throwing if it fails. + /// + /// - Parameter policy: The `SecPolicy`. + /// + /// - Returns: `self`, with the policy applied. + /// - Throws: An `AFError.serverTrustEvaluationFailed` instance with a `.policyApplicationFailed` reason. + public func apply(policy: SecPolicy) throws -> SecTrust { + let status = SecTrustSetPolicies(type, policy) + + guard status.af.isSuccess else { + throw AFError.serverTrustEvaluationFailed(reason: .policyApplicationFailed(trust: type, + policy: policy, + status: status)) + } + + return type + } + + /// Evaluate `self`, throwing an `Error` if evaluation fails. + /// + /// - Throws: `AFError.serverTrustEvaluationFailed` with reason `.trustValidationFailed` and associated error from + /// the underlying evaluation. + @available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, *) + public func evaluate() throws { + var error: CFError? + let evaluationSucceeded = SecTrustEvaluateWithError(type, &error) + + if !evaluationSucceeded { + throw AFError.serverTrustEvaluationFailed(reason: .trustEvaluationFailed(error: error)) + } + } + + /// Validate `self`, passing any failure values through `errorProducer`. + /// + /// - Parameter errorProducer: The closure used to transform the failed `OSStatus` and `SecTrustResultType` into an + /// `Error`. + /// - Throws: The `Error` produced by the `errorProducer` closure. + @available(iOS, introduced: 10, deprecated: 12, renamed: "evaluate()") + @available(macOS, introduced: 10.12, deprecated: 10.14, renamed: "evaluate()") + @available(tvOS, introduced: 10, deprecated: 12, renamed: "evaluate()") + @available(watchOS, introduced: 3, deprecated: 5, renamed: "evaluate()") + public func validate(errorProducer: (_ status: OSStatus, _ result: SecTrustResultType) -> Error) throws { + var result = SecTrustResultType.invalid + let status = SecTrustEvaluate(type, &result) + + guard status.af.isSuccess && result.af.isSuccess else { + throw errorProducer(status, result) + } + } + + /// Sets a custom certificate chain on `self`, allowing full validation of a self-signed certificate and its chain. + /// + /// - Parameter certificates: The `SecCertificate`s to add to the chain. + /// - Throws: Any error produced when applying the new certificate chain. + public func setAnchorCertificates(_ certificates: [SecCertificate]) throws { + // Add additional anchor certificates. + let status = SecTrustSetAnchorCertificates(type, certificates as CFArray) + guard status.af.isSuccess else { + throw AFError.serverTrustEvaluationFailed(reason: .settingAnchorCertificatesFailed(status: status, + certificates: certificates)) + } + + // Trust only the set anchor certs. + let onlyStatus = SecTrustSetAnchorCertificatesOnly(type, true) + guard onlyStatus.af.isSuccess else { + throw AFError.serverTrustEvaluationFailed(reason: .settingAnchorCertificatesFailed(status: onlyStatus, + certificates: certificates)) + } + } + + /// The public keys contained in `self`. + public var publicKeys: [SecKey] { + certificates.af.publicKeys + } + + /// The `SecCertificate`s contained i `self`. + public var certificates: [SecCertificate] { + (0.. SecPolicy { + SecPolicyCreateSSL(true, hostname as CFString) + } + + /// Creates a `SecPolicy` which checks the revocation of certificates. + /// + /// - Parameter options: The `RevocationTrustEvaluator.Options` for evaluation. + /// + /// - Returns: The `SecPolicy`. + /// - Throws: An `AFError.serverTrustEvaluationFailed` error with reason `.revocationPolicyCreationFailed` + /// if the policy cannot be created. + public static func revocation(options: RevocationTrustEvaluator.Options) throws -> SecPolicy { + guard let policy = SecPolicyCreateRevocation(options.rawValue) else { + throw AFError.serverTrustEvaluationFailed(reason: .revocationPolicyCreationFailed) + } + + return policy + } +} + +extension Array: AlamofireExtended {} +extension AlamofireExtension where ExtendedType == [SecCertificate] { + /// All `Data` values for the contained `SecCertificate`s. + public var data: [Data] { + type.map { SecCertificateCopyData($0) as Data } + } + + /// All public `SecKey` values for the contained `SecCertificate`s. + public var publicKeys: [SecKey] { + type.compactMap(\.af.publicKey) + } +} + +extension SecCertificate: AlamofireExtended {} +extension AlamofireExtension where ExtendedType == SecCertificate { + /// The public key for `self`, if it can be extracted. + public var publicKey: SecKey? { + let policy = SecPolicyCreateBasicX509() + var trust: SecTrust? + let trustCreationStatus = SecTrustCreateWithCertificates(type, policy, &trust) + + guard let createdTrust = trust, trustCreationStatus == errSecSuccess else { return nil } + + return SecTrustCopyPublicKey(createdTrust) + } +} + +extension OSStatus: AlamofireExtended {} +extension AlamofireExtension where ExtendedType == OSStatus { + /// Returns whether `self` is `errSecSuccess`. + public var isSuccess: Bool { type == errSecSuccess } +} + +extension SecTrustResultType: AlamofireExtended {} +extension AlamofireExtension where ExtendedType == SecTrustResultType { + /// Returns whether `self is `.unspecified` or `.proceed`. + public var isSuccess: Bool { + type == .unspecified || type == .proceed + } +} +#endif diff --git a/Instagram-Clone/Pods/Alamofire/Source/Session.swift b/Instagram-Clone/Pods/Alamofire/Source/Session.swift new file mode 100644 index 0000000..4588811 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/Session.swift @@ -0,0 +1,1265 @@ +// +// Session.swift +// +// Copyright (c) 2014-2018 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 + +/// `Session` creates and manages Alamofire's `Request` types during their lifetimes. It also provides common +/// functionality for all `Request`s, including queuing, interception, trust management, redirect handling, and response +/// cache handling. +open class Session { + /// Shared singleton instance used by all `AF.request` APIs. Cannot be modified. + public static let `default` = Session() + + /// Underlying `URLSession` used to create `URLSessionTasks` for this instance, and for which this instance's + /// `delegate` handles `URLSessionDelegate` callbacks. + /// + /// - Note: This instance should **NOT** be used to interact with the underlying `URLSessionTask`s. Doing so will + /// break internal Alamofire logic that tracks those tasks. + /// + public let session: URLSession + /// Instance's `SessionDelegate`, which handles the `URLSessionDelegate` methods and `Request` interaction. + public let delegate: SessionDelegate + /// Root `DispatchQueue` for all internal callbacks and state update. **MUST** be a serial queue. + public let rootQueue: DispatchQueue + /// Value determining whether this instance automatically calls `resume()` on all created `Request`s. + public let startRequestsImmediately: Bool + /// `DispatchQueue` on which `URLRequest`s are created asynchronously. By default this queue uses `rootQueue` as its + /// `target`, but a separate queue can be used if request creation is determined to be a bottleneck. Always profile + /// and test before introducing an additional queue. + public let requestQueue: DispatchQueue + /// `DispatchQueue` passed to all `Request`s on which they perform their response serialization. By default this + /// queue uses `rootQueue` as its `target` but a separate queue can be used if response serialization is determined + /// to be a bottleneck. Always profile and test before introducing an additional queue. + public let serializationQueue: DispatchQueue + /// `RequestInterceptor` used for all `Request` created by the instance. `RequestInterceptor`s can also be set on a + /// per-`Request` basis, in which case the `Request`'s interceptor takes precedence over this value. + public let interceptor: RequestInterceptor? + /// `ServerTrustManager` instance used to evaluate all trust challenges and provide certificate and key pinning. + public let serverTrustManager: ServerTrustManager? + /// `RedirectHandler` instance used to provide customization for request redirection. + public let redirectHandler: RedirectHandler? + /// `CachedResponseHandler` instance used to provide customization of cached response handling. + public let cachedResponseHandler: CachedResponseHandler? + /// `CompositeEventMonitor` used to compose Alamofire's `defaultEventMonitors` and any passed `EventMonitor`s. + public let eventMonitor: CompositeEventMonitor + /// `EventMonitor`s included in all instances. `[AlamofireNotifications()]` by default. + public let defaultEventMonitors: [EventMonitor] = [AlamofireNotifications()] + + /// Internal map between `Request`s and any `URLSessionTasks` that may be in flight for them. + var requestTaskMap = RequestTaskMap() + /// `Set` of currently active `Request`s. + var activeRequests: Set = [] + /// Completion events awaiting `URLSessionTaskMetrics`. + var waitingCompletions: [URLSessionTask: () -> Void] = [:] + + /// Creates a `Session` from a `URLSession` and other parameters. + /// + /// - Note: When passing a `URLSession`, you must create the `URLSession` with a specific `delegateQueue` value and + /// pass the `delegateQueue`'s `underlyingQueue` as the `rootQueue` parameter of this initializer. + /// + /// - Parameters: + /// - session: Underlying `URLSession` for this instance. + /// - delegate: `SessionDelegate` that handles `session`'s delegate callbacks as well as `Request` + /// interaction. + /// - rootQueue: Root `DispatchQueue` for all internal callbacks and state updates. **MUST** be a + /// serial queue. + /// - startRequestsImmediately: Determines whether this instance will automatically start all `Request`s. `true` + /// by default. If set to `false`, all `Request`s created must have `.resume()` called. + /// on them for them to start. + /// - requestQueue: `DispatchQueue` on which to perform `URLRequest` creation. By default this queue + /// will use the `rootQueue` as its `target`. A separate queue can be used if it's + /// determined request creation is a bottleneck, but that should only be done after + /// careful testing and profiling. `nil` by default. + /// - serializationQueue: `DispatchQueue` on which to perform all response serialization. By default this + /// queue will use the `rootQueue` as its `target`. A separate queue can be used if + /// it's determined response serialization is a bottleneck, but that should only be + /// done after careful testing and profiling. `nil` by default. + /// - interceptor: `RequestInterceptor` to be used for all `Request`s created by this instance. `nil` + /// by default. + /// - serverTrustManager: `ServerTrustManager` to be used for all trust evaluations by this instance. `nil` + /// by default. + /// - redirectHandler: `RedirectHandler` to be used by all `Request`s created by this instance. `nil` by + /// default. + /// - cachedResponseHandler: `CachedResponseHandler` to be used by all `Request`s created by this instance. + /// `nil` by default. + /// - eventMonitors: Additional `EventMonitor`s used by the instance. Alamofire always adds a + /// `AlamofireNotifications` `EventMonitor` to the array passed here. `[]` by default. + public init(session: URLSession, + delegate: SessionDelegate, + rootQueue: DispatchQueue, + startRequestsImmediately: Bool = true, + requestQueue: DispatchQueue? = nil, + serializationQueue: DispatchQueue? = nil, + interceptor: RequestInterceptor? = nil, + serverTrustManager: ServerTrustManager? = nil, + redirectHandler: RedirectHandler? = nil, + cachedResponseHandler: CachedResponseHandler? = nil, + eventMonitors: [EventMonitor] = []) { + precondition(session.configuration.identifier == nil, + "Alamofire does not support background URLSessionConfigurations.") + precondition(session.delegateQueue.underlyingQueue === rootQueue, + "Session(session:) initializer must be passed the DispatchQueue used as the delegateQueue's underlyingQueue as rootQueue.") + + self.session = session + self.delegate = delegate + self.rootQueue = rootQueue + self.startRequestsImmediately = startRequestsImmediately + self.requestQueue = requestQueue ?? DispatchQueue(label: "\(rootQueue.label).requestQueue", target: rootQueue) + self.serializationQueue = serializationQueue ?? DispatchQueue(label: "\(rootQueue.label).serializationQueue", target: rootQueue) + self.interceptor = interceptor + self.serverTrustManager = serverTrustManager + self.redirectHandler = redirectHandler + self.cachedResponseHandler = cachedResponseHandler + eventMonitor = CompositeEventMonitor(monitors: defaultEventMonitors + eventMonitors) + delegate.eventMonitor = eventMonitor + delegate.stateProvider = self + } + + /// Creates a `Session` from a `URLSessionConfiguration`. + /// + /// - Note: This initializer lets Alamofire handle the creation of the underlying `URLSession` and its + /// `delegateQueue`, and is the recommended initializer for most uses. + /// + /// - Parameters: + /// - configuration: `URLSessionConfiguration` to be used to create the underlying `URLSession`. Changes + /// to this value after being passed to this initializer will have no effect. + /// `URLSessionConfiguration.af.default` by default. + /// - delegate: `SessionDelegate` that handles `session`'s delegate callbacks as well as `Request` + /// interaction. `SessionDelegate()` by default. + /// - rootQueue: Root `DispatchQueue` for all internal callbacks and state updates. **MUST** be a + /// serial queue. `DispatchQueue(label: "org.alamofire.session.rootQueue")` by default. + /// - startRequestsImmediately: Determines whether this instance will automatically start all `Request`s. `true` + /// by default. If set to `false`, all `Request`s created must have `.resume()` called. + /// on them for them to start. + /// - requestQueue: `DispatchQueue` on which to perform `URLRequest` creation. By default this queue + /// will use the `rootQueue` as its `target`. A separate queue can be used if it's + /// determined request creation is a bottleneck, but that should only be done after + /// careful testing and profiling. `nil` by default. + /// - serializationQueue: `DispatchQueue` on which to perform all response serialization. By default this + /// queue will use the `rootQueue` as its `target`. A separate queue can be used if + /// it's determined response serialization is a bottleneck, but that should only be + /// done after careful testing and profiling. `nil` by default. + /// - interceptor: `RequestInterceptor` to be used for all `Request`s created by this instance. `nil` + /// by default. + /// - serverTrustManager: `ServerTrustManager` to be used for all trust evaluations by this instance. `nil` + /// by default. + /// - redirectHandler: `RedirectHandler` to be used by all `Request`s created by this instance. `nil` by + /// default. + /// - cachedResponseHandler: `CachedResponseHandler` to be used by all `Request`s created by this instance. + /// `nil` by default. + /// - eventMonitors: Additional `EventMonitor`s used by the instance. Alamofire always adds a + /// `AlamofireNotifications` `EventMonitor` to the array passed here. `[]` by default. + public convenience init(configuration: URLSessionConfiguration = URLSessionConfiguration.af.default, + delegate: SessionDelegate = SessionDelegate(), + rootQueue: DispatchQueue = DispatchQueue(label: "org.alamofire.session.rootQueue"), + startRequestsImmediately: Bool = true, + requestQueue: DispatchQueue? = nil, + serializationQueue: DispatchQueue? = nil, + interceptor: RequestInterceptor? = nil, + serverTrustManager: ServerTrustManager? = nil, + redirectHandler: RedirectHandler? = nil, + cachedResponseHandler: CachedResponseHandler? = nil, + eventMonitors: [EventMonitor] = []) { + precondition(configuration.identifier == nil, "Alamofire does not support background URLSessionConfigurations.") + + // Retarget the incoming rootQueue for safety, unless it's the main queue, which we know is safe. + let serialRootQueue = (rootQueue === DispatchQueue.main) ? rootQueue : DispatchQueue(label: rootQueue.label, + target: rootQueue) + let delegateQueue = OperationQueue(maxConcurrentOperationCount: 1, underlyingQueue: serialRootQueue, name: "\(serialRootQueue.label).sessionDelegate") + let session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: delegateQueue) + + self.init(session: session, + delegate: delegate, + rootQueue: serialRootQueue, + startRequestsImmediately: startRequestsImmediately, + requestQueue: requestQueue, + serializationQueue: serializationQueue, + interceptor: interceptor, + serverTrustManager: serverTrustManager, + redirectHandler: redirectHandler, + cachedResponseHandler: cachedResponseHandler, + eventMonitors: eventMonitors) + } + + deinit { + finishRequestsForDeinit() + session.invalidateAndCancel() + } + + // MARK: - All Requests API + + /// Perform an action on all active `Request`s. + /// + /// - Note: The provided `action` closure is performed asynchronously, meaning that some `Request`s may complete and + /// be unavailable by time it runs. Additionally, this action is performed on the instances's `rootQueue`, + /// so care should be taken that actions are fast. Once the work on the `Request`s is complete, any + /// additional work should be performed on another queue. + /// + /// - Parameters: + /// - action: Closure to perform with all `Request`s. + public func withAllRequests(perform action: @escaping (Set) -> Void) { + rootQueue.async { + action(self.activeRequests) + } + } + + /// Cancel all active `Request`s, optionally calling a completion handler when complete. + /// + /// - Note: This is an asynchronous operation and does not block the creation of future `Request`s. Cancelled + /// `Request`s may not cancel immediately due internal work, and may not cancel at all if they are close to + /// completion when cancelled. + /// + /// - Parameters: + /// - queue: `DispatchQueue` on which the completion handler is run. `.main` by default. + /// - completion: Closure to be called when all `Request`s have been cancelled. + public func cancelAllRequests(completingOnQueue queue: DispatchQueue = .main, completion: (() -> Void)? = nil) { + withAllRequests { requests in + requests.forEach { $0.cancel() } + queue.async { + completion?() + } + } + } + + // MARK: - DataRequest + + /// Closure which provides a `URLRequest` for mutation. + public typealias RequestModifier = (inout URLRequest) throws -> Void + + struct RequestConvertible: URLRequestConvertible { + let url: URLConvertible + let method: HTTPMethod + let parameters: Parameters? + let encoding: ParameterEncoding + let headers: HTTPHeaders? + let requestModifier: RequestModifier? + + func asURLRequest() throws -> URLRequest { + var request = try URLRequest(url: url, method: method, headers: headers) + try requestModifier?(&request) + + return try encoding.encode(request, with: parameters) + } + } + + /// Creates a `DataRequest` from a `URLRequest` created using the passed components and a `RequestInterceptor`. + /// + /// - Parameters: + /// - convertible: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - method: `HTTPMethod` for the `URLRequest`. `.get` by default. + /// - parameters: `Parameters` (a.k.a. `[String: Any]`) value to be encoded into the `URLRequest`. `nil` by + /// default. + /// - encoding: `ParameterEncoding` to be used to encode the `parameters` value into the `URLRequest`. + /// `URLEncoding.default` by default. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided + /// parameters. `nil` by default. + /// + /// - Returns: The created `DataRequest`. + open func request(_ convertible: URLConvertible, + method: HTTPMethod = .get, + parameters: Parameters? = nil, + encoding: ParameterEncoding = URLEncoding.default, + headers: HTTPHeaders? = nil, + interceptor: RequestInterceptor? = nil, + requestModifier: RequestModifier? = nil) -> DataRequest { + let convertible = RequestConvertible(url: convertible, + method: method, + parameters: parameters, + encoding: encoding, + headers: headers, + requestModifier: requestModifier) + + return request(convertible, interceptor: interceptor) + } + + struct RequestEncodableConvertible: URLRequestConvertible { + let url: URLConvertible + let method: HTTPMethod + let parameters: Parameters? + let encoder: ParameterEncoder + let headers: HTTPHeaders? + let requestModifier: RequestModifier? + + func asURLRequest() throws -> URLRequest { + var request = try URLRequest(url: url, method: method, headers: headers) + try requestModifier?(&request) + + return try parameters.map { try encoder.encode($0, into: request) } ?? request + } + } + + /// Creates a `DataRequest` from a `URLRequest` created using the passed components, `Encodable` parameters, and a + /// `RequestInterceptor`. + /// + /// - Parameters: + /// - convertible: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - method: `HTTPMethod` for the `URLRequest`. `.get` by default. + /// - parameters: `Encodable` value to be encoded into the `URLRequest`. `nil` by default. + /// - encoder: `ParameterEncoder` to be used to encode the `parameters` value into the `URLRequest`. + /// `URLEncodedFormParameterEncoder.default` by default. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from + /// the provided parameters. `nil` by default. + /// + /// - Returns: The created `DataRequest`. + open func request(_ convertible: URLConvertible, + method: HTTPMethod = .get, + parameters: Parameters? = nil, + encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default, + headers: HTTPHeaders? = nil, + interceptor: RequestInterceptor? = nil, + requestModifier: RequestModifier? = nil) -> DataRequest { + let convertible = RequestEncodableConvertible(url: convertible, + method: method, + parameters: parameters, + encoder: encoder, + headers: headers, + requestModifier: requestModifier) + + return request(convertible, interceptor: interceptor) + } + + /// Creates a `DataRequest` from a `URLRequestConvertible` value and a `RequestInterceptor`. + /// + /// - Parameters: + /// - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// + /// - Returns: The created `DataRequest`. + open func request(_ convertible: URLRequestConvertible, interceptor: RequestInterceptor? = nil) -> DataRequest { + let request = DataRequest(convertible: convertible, + underlyingQueue: rootQueue, + serializationQueue: serializationQueue, + eventMonitor: eventMonitor, + interceptor: interceptor, + delegate: self) + + perform(request) + + return request + } + + // MARK: - DataStreamRequest + + /// Creates a `DataStreamRequest` from the passed components, `Encodable` parameters, and `RequestInterceptor`. + /// + /// - Parameters: + /// - convertible: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - method: `HTTPMethod` for the `URLRequest`. `.get` by default. + /// - parameters: `Encodable` value to be encoded into the `URLRequest`. `nil` by default. + /// - encoder: `ParameterEncoder` to be used to encode the `parameters` value into the + /// `URLRequest`. + /// `URLEncodedFormParameterEncoder.default` by default. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - automaticallyCancelOnStreamError: `Bool` indicating whether the instance should be canceled when an `Error` + /// is thrown while serializing stream `Data`. `false` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` + /// by default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from + /// the provided parameters. `nil` by default. + /// + /// - Returns: The created `DataStream` request. + open func streamRequest(_ convertible: URLConvertible, + method: HTTPMethod = .get, + parameters: Parameters? = nil, + encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default, + headers: HTTPHeaders? = nil, + automaticallyCancelOnStreamError: Bool = false, + interceptor: RequestInterceptor? = nil, + requestModifier: RequestModifier? = nil) -> DataStreamRequest { + let convertible = RequestEncodableConvertible(url: convertible, + method: method, + parameters: parameters, + encoder: encoder, + headers: headers, + requestModifier: requestModifier) + + return streamRequest(convertible, + automaticallyCancelOnStreamError: automaticallyCancelOnStreamError, + interceptor: interceptor) + } + + /// Creates a `DataStreamRequest` from the passed components and `RequestInterceptor`. + /// + /// - Parameters: + /// - convertible: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - method: `HTTPMethod` for the `URLRequest`. `.get` by default. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - automaticallyCancelOnStreamError: `Bool` indicating whether the instance should be canceled when an `Error` + /// is thrown while serializing stream `Data`. `false` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` + /// by default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from + /// the provided parameters. `nil` by default. + /// + /// - Returns: The created `DataStream` request. + open func streamRequest(_ convertible: URLConvertible, + method: HTTPMethod = .get, + headers: HTTPHeaders? = nil, + automaticallyCancelOnStreamError: Bool = false, + interceptor: RequestInterceptor? = nil, + requestModifier: RequestModifier? = nil) -> DataStreamRequest { + let convertible = RequestEncodableConvertible(url: convertible, + method: method, + parameters: Empty?.none, + encoder: URLEncodedFormParameterEncoder.default, + headers: headers, + requestModifier: requestModifier) + + return streamRequest(convertible, + automaticallyCancelOnStreamError: automaticallyCancelOnStreamError, + interceptor: interceptor) + } + + /// Creates a `DataStreamRequest` from the passed `URLRequestConvertible` value and `RequestInterceptor`. + /// + /// - Parameters: + /// - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`. + /// - automaticallyCancelOnStreamError: `Bool` indicating whether the instance should be canceled when an `Error` + /// is thrown while serializing stream `Data`. `false` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` + /// by default. + /// + /// - Returns: The created `DataStreamRequest`. + open func streamRequest(_ convertible: URLRequestConvertible, + automaticallyCancelOnStreamError: Bool = false, + interceptor: RequestInterceptor? = nil) -> DataStreamRequest { + let request = DataStreamRequest(convertible: convertible, + automaticallyCancelOnStreamError: automaticallyCancelOnStreamError, + underlyingQueue: rootQueue, + serializationQueue: serializationQueue, + eventMonitor: eventMonitor, + interceptor: interceptor, + delegate: self) + + perform(request) + + return request + } + + // MARK: - DownloadRequest + + /// Creates a `DownloadRequest` using a `URLRequest` created using the passed components, `RequestInterceptor`, and + /// `Destination`. + /// + /// - Parameters: + /// - convertible: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - method: `HTTPMethod` for the `URLRequest`. `.get` by default. + /// - parameters: `Parameters` (a.k.a. `[String: Any]`) value to be encoded into the `URLRequest`. `nil` by + /// default. + /// - encoding: `ParameterEncoding` to be used to encode the `parameters` value into the `URLRequest`. + /// Defaults to `URLEncoding.default`. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided + /// parameters. `nil` by default. + /// - destination: `DownloadRequest.Destination` closure used to determine how and where the downloaded file + /// should be moved. `nil` by default. + /// + /// - Returns: The created `DownloadRequest`. + open func download(_ convertible: URLConvertible, + method: HTTPMethod = .get, + parameters: Parameters? = nil, + encoding: ParameterEncoding = URLEncoding.default, + headers: HTTPHeaders? = nil, + interceptor: RequestInterceptor? = nil, + requestModifier: RequestModifier? = nil, + to destination: DownloadRequest.Destination? = nil) -> DownloadRequest { + let convertible = RequestConvertible(url: convertible, + method: method, + parameters: parameters, + encoding: encoding, + headers: headers, + requestModifier: requestModifier) + + return download(convertible, interceptor: interceptor, to: destination) + } + + /// Creates a `DownloadRequest` from a `URLRequest` created using the passed components, `Encodable` parameters, and + /// a `RequestInterceptor`. + /// + /// - Parameters: + /// - convertible: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - method: `HTTPMethod` for the `URLRequest`. `.get` by default. + /// - parameters: Value conforming to `Encodable` to be encoded into the `URLRequest`. `nil` by default. + /// - encoder: `ParameterEncoder` to be used to encode the `parameters` value into the `URLRequest`. + /// Defaults to `URLEncodedFormParameterEncoder.default`. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided + /// parameters. `nil` by default. + /// - destination: `DownloadRequest.Destination` closure used to determine how and where the downloaded file + /// should be moved. `nil` by default. + /// + /// - Returns: The created `DownloadRequest`. + open func download(_ convertible: URLConvertible, + method: HTTPMethod = .get, + parameters: Parameters? = nil, + encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default, + headers: HTTPHeaders? = nil, + interceptor: RequestInterceptor? = nil, + requestModifier: RequestModifier? = nil, + to destination: DownloadRequest.Destination? = nil) -> DownloadRequest { + let convertible = RequestEncodableConvertible(url: convertible, + method: method, + parameters: parameters, + encoder: encoder, + headers: headers, + requestModifier: requestModifier) + + return download(convertible, interceptor: interceptor, to: destination) + } + + /// Creates a `DownloadRequest` from a `URLRequestConvertible` value, a `RequestInterceptor`, and a `Destination`. + /// + /// - Parameters: + /// - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - destination: `DownloadRequest.Destination` closure used to determine how and where the downloaded file + /// should be moved. `nil` by default. + /// + /// - Returns: The created `DownloadRequest`. + open func download(_ convertible: URLRequestConvertible, + interceptor: RequestInterceptor? = nil, + to destination: DownloadRequest.Destination? = nil) -> DownloadRequest { + let request = DownloadRequest(downloadable: .request(convertible), + underlyingQueue: rootQueue, + serializationQueue: serializationQueue, + eventMonitor: eventMonitor, + interceptor: interceptor, + delegate: self, + destination: destination ?? DownloadRequest.defaultDestination) + + perform(request) + + return request + } + + /// Creates a `DownloadRequest` from the `resumeData` produced from a previously cancelled `DownloadRequest`, as + /// well as a `RequestInterceptor`, and a `Destination`. + /// + /// - Note: If `destination` is not specified, the download will be moved to a temporary location determined by + /// Alamofire. The file will not be deleted until the system purges the temporary files. + /// + /// - Note: On some versions of all Apple platforms (iOS 10 - 10.2, macOS 10.12 - 10.12.2, tvOS 10 - 10.1, watchOS 3 - 3.1.1), + /// `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 [this Stack Overflow post](http://stackoverflow.com/a/39347461/1342462). + /// + /// - Parameters: + /// - data: The resume data from a previously cancelled `DownloadRequest` or `URLSessionDownloadTask`. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - destination: `DownloadRequest.Destination` closure used to determine how and where the downloaded file + /// should be moved. `nil` by default. + /// + /// - Returns: The created `DownloadRequest`. + open func download(resumingWith data: Data, + interceptor: RequestInterceptor? = nil, + to destination: DownloadRequest.Destination? = nil) -> DownloadRequest { + let request = DownloadRequest(downloadable: .resumeData(data), + underlyingQueue: rootQueue, + serializationQueue: serializationQueue, + eventMonitor: eventMonitor, + interceptor: interceptor, + delegate: self, + destination: destination ?? DownloadRequest.defaultDestination) + + perform(request) + + return request + } + + // MARK: - UploadRequest + + struct ParameterlessRequestConvertible: URLRequestConvertible { + let url: URLConvertible + let method: HTTPMethod + let headers: HTTPHeaders? + let requestModifier: RequestModifier? + + func asURLRequest() throws -> URLRequest { + var request = try URLRequest(url: url, method: method, headers: headers) + try requestModifier?(&request) + + return request + } + } + + struct Upload: UploadConvertible { + let request: URLRequestConvertible + let uploadable: UploadableConvertible + + func createUploadable() throws -> UploadRequest.Uploadable { + try uploadable.createUploadable() + } + + func asURLRequest() throws -> URLRequest { + try request.asURLRequest() + } + } + + // MARK: Data + + /// Creates an `UploadRequest` for the given `Data`, `URLRequest` components, and `RequestInterceptor`. + /// + /// - Parameters: + /// - data: The `Data` to upload. + /// - convertible: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - method: `HTTPMethod` for the `URLRequest`. `.post` by default. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by + /// default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided + /// parameters. `nil` by default. + /// + /// - Returns: The created `UploadRequest`. + open func upload(_ data: Data, + to convertible: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil, + interceptor: RequestInterceptor? = nil, + fileManager: FileManager = .default, + requestModifier: RequestModifier? = nil) -> UploadRequest { + let convertible = ParameterlessRequestConvertible(url: convertible, + method: method, + headers: headers, + requestModifier: requestModifier) + + return upload(data, with: convertible, interceptor: interceptor, fileManager: fileManager) + } + + /// Creates an `UploadRequest` for the given `Data` using the `URLRequestConvertible` value and `RequestInterceptor`. + /// + /// - Parameters: + /// - data: The `Data` to upload. + /// - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by + /// default. + /// + /// - Returns: The created `UploadRequest`. + open func upload(_ data: Data, + with convertible: URLRequestConvertible, + interceptor: RequestInterceptor? = nil, + fileManager: FileManager = .default) -> UploadRequest { + upload(.data(data), with: convertible, interceptor: interceptor, fileManager: fileManager) + } + + // MARK: File + + /// Creates an `UploadRequest` for the file at the given file `URL`, using a `URLRequest` from the provided + /// components and `RequestInterceptor`. + /// + /// - Parameters: + /// - fileURL: The `URL` of the file to upload. + /// - convertible: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - method: `HTTPMethod` for the `URLRequest`. `.post` by default. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `UploadRequest`. `nil` by default. + /// - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by + /// default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided + /// parameters. `nil` by default. + /// + /// - Returns: The created `UploadRequest`. + open func upload(_ fileURL: URL, + to convertible: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil, + interceptor: RequestInterceptor? = nil, + fileManager: FileManager = .default, + requestModifier: RequestModifier? = nil) -> UploadRequest { + let convertible = ParameterlessRequestConvertible(url: convertible, + method: method, + headers: headers, + requestModifier: requestModifier) + + return upload(fileURL, with: convertible, interceptor: interceptor, fileManager: fileManager) + } + + /// Creates an `UploadRequest` for the file at the given file `URL` using the `URLRequestConvertible` value and + /// `RequestInterceptor`. + /// + /// - Parameters: + /// - fileURL: The `URL` of the file to upload. + /// - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by + /// default. + /// + /// - Returns: The created `UploadRequest`. + open func upload(_ fileURL: URL, + with convertible: URLRequestConvertible, + interceptor: RequestInterceptor? = nil, + fileManager: FileManager = .default) -> UploadRequest { + upload(.file(fileURL, shouldRemove: false), with: convertible, interceptor: interceptor, fileManager: fileManager) + } + + // MARK: InputStream + + /// Creates an `UploadRequest` from the `InputStream` provided using a `URLRequest` from the provided components and + /// `RequestInterceptor`. + /// + /// - Parameters: + /// - stream: The `InputStream` that provides the data to upload. + /// - convertible: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - method: `HTTPMethod` for the `URLRequest`. `.post` by default. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by + /// default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided + /// parameters. `nil` by default. + /// + /// - Returns: The created `UploadRequest`. + open func upload(_ stream: InputStream, + to convertible: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil, + interceptor: RequestInterceptor? = nil, + fileManager: FileManager = .default, + requestModifier: RequestModifier? = nil) -> UploadRequest { + let convertible = ParameterlessRequestConvertible(url: convertible, + method: method, + headers: headers, + requestModifier: requestModifier) + + return upload(stream, with: convertible, interceptor: interceptor, fileManager: fileManager) + } + + /// Creates an `UploadRequest` from the provided `InputStream` using the `URLRequestConvertible` value and + /// `RequestInterceptor`. + /// + /// - Parameters: + /// - stream: The `InputStream` that provides the data to upload. + /// - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by + /// default. + /// + /// - Returns: The created `UploadRequest`. + open func upload(_ stream: InputStream, + with convertible: URLRequestConvertible, + interceptor: RequestInterceptor? = nil, + fileManager: FileManager = .default) -> UploadRequest { + upload(.stream(stream), with: convertible, interceptor: interceptor, fileManager: fileManager) + } + + // MARK: MultipartFormData + + /// Creates an `UploadRequest` for the multipart form data built using a closure and sent using the provided + /// `URLRequest` components and `RequestInterceptor`. + /// + /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cumulative + /// 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. + /// + /// - Parameters: + /// - multipartFormData: `MultipartFormData` building closure. + /// - url: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - encodingMemoryThreshold: Byte threshold used to determine whether the form data is encoded into memory or + /// onto disk before being uploaded. `MultipartFormData.encodingMemoryThreshold` by + /// default. + /// - method: `HTTPMethod` for the `URLRequest`. `.post` by default. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - fileManager: `FileManager` to be used if the form data exceeds the memory threshold and is + /// written to disk before being uploaded. `.default` instance by default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the + /// provided parameters. `nil` by default. + /// + /// - Returns: The created `UploadRequest`. + open func upload(multipartFormData: @escaping (MultipartFormData) -> Void, + to url: URLConvertible, + usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil, + interceptor: RequestInterceptor? = nil, + fileManager: FileManager = .default, + requestModifier: RequestModifier? = nil) -> UploadRequest { + let convertible = ParameterlessRequestConvertible(url: url, + method: method, + headers: headers, + requestModifier: requestModifier) + + let formData = MultipartFormData(fileManager: fileManager) + multipartFormData(formData) + + return upload(multipartFormData: formData, + with: convertible, + usingThreshold: encodingMemoryThreshold, + interceptor: interceptor, + fileManager: fileManager) + } + + /// Creates an `UploadRequest` using a `MultipartFormData` building closure, the provided `URLRequestConvertible` + /// value, and a `RequestInterceptor`. + /// + /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cumulative + /// 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. + /// + /// - Parameters: + /// - multipartFormData: `MultipartFormData` building closure. + /// - request: `URLRequestConvertible` value to be used to create the `URLRequest`. + /// - encodingMemoryThreshold: Byte threshold used to determine whether the form data is encoded into memory or + /// onto disk before being uploaded. `MultipartFormData.encodingMemoryThreshold` by + /// default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - fileManager: `FileManager` to be used if the form data exceeds the memory threshold and is + /// written to disk before being uploaded. `.default` instance by default. + /// + /// - Returns: The created `UploadRequest`. + open func upload(multipartFormData: @escaping (MultipartFormData) -> Void, + with request: URLRequestConvertible, + usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold, + interceptor: RequestInterceptor? = nil, + fileManager: FileManager = .default) -> UploadRequest { + let formData = MultipartFormData(fileManager: fileManager) + multipartFormData(formData) + + return upload(multipartFormData: formData, + with: request, + usingThreshold: encodingMemoryThreshold, + interceptor: interceptor, + fileManager: fileManager) + } + + /// Creates an `UploadRequest` for the prebuilt `MultipartFormData` value using the provided `URLRequest` components + /// and `RequestInterceptor`. + /// + /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cumulative + /// 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. + /// + /// - Parameters: + /// - multipartFormData: `MultipartFormData` instance to upload. + /// - url: `URLConvertible` value to be used as the `URLRequest`'s `URL`. + /// - encodingMemoryThreshold: Byte threshold used to determine whether the form data is encoded into memory or + /// onto disk before being uploaded. `MultipartFormData.encodingMemoryThreshold` by + /// default. + /// - method: `HTTPMethod` for the `URLRequest`. `.post` by default. + /// - headers: `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - fileManager: `FileManager` to be used if the form data exceeds the memory threshold and is + /// written to disk before being uploaded. `.default` instance by default. + /// - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the + /// provided parameters. `nil` by default. + /// + /// - Returns: The created `UploadRequest`. + open func upload(multipartFormData: MultipartFormData, + to url: URLConvertible, + usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil, + interceptor: RequestInterceptor? = nil, + fileManager: FileManager = .default, + requestModifier: RequestModifier? = nil) -> UploadRequest { + let convertible = ParameterlessRequestConvertible(url: url, + method: method, + headers: headers, + requestModifier: requestModifier) + + let multipartUpload = MultipartUpload(encodingMemoryThreshold: encodingMemoryThreshold, + request: convertible, + multipartFormData: multipartFormData) + + return upload(multipartUpload, interceptor: interceptor, fileManager: fileManager) + } + + /// Creates an `UploadRequest` for the prebuilt `MultipartFormData` value using the providing `URLRequestConvertible` + /// value and `RequestInterceptor`. + /// + /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cumulative + /// 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. + /// + /// - Parameters: + /// - multipartFormData: `MultipartFormData` instance to upload. + /// - request: `URLRequestConvertible` value to be used to create the `URLRequest`. + /// - encodingMemoryThreshold: Byte threshold used to determine whether the form data is encoded into memory or + /// onto disk before being uploaded. `MultipartFormData.encodingMemoryThreshold` by + /// default. + /// - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default. + /// - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by + /// default. + /// + /// - Returns: The created `UploadRequest`. + open func upload(multipartFormData: MultipartFormData, + with request: URLRequestConvertible, + usingThreshold encodingMemoryThreshold: UInt64 = MultipartFormData.encodingMemoryThreshold, + interceptor: RequestInterceptor? = nil, + fileManager: FileManager = .default) -> UploadRequest { + let multipartUpload = MultipartUpload(encodingMemoryThreshold: encodingMemoryThreshold, + request: request, + multipartFormData: multipartFormData) + + return upload(multipartUpload, interceptor: interceptor, fileManager: fileManager) + } + + // MARK: - Internal API + + // MARK: Uploadable + + func upload(_ uploadable: UploadRequest.Uploadable, + with convertible: URLRequestConvertible, + interceptor: RequestInterceptor?, + fileManager: FileManager) -> UploadRequest { + let uploadable = Upload(request: convertible, uploadable: uploadable) + + return upload(uploadable, interceptor: interceptor, fileManager: fileManager) + } + + func upload(_ upload: UploadConvertible, interceptor: RequestInterceptor?, fileManager: FileManager) -> UploadRequest { + let request = UploadRequest(convertible: upload, + underlyingQueue: rootQueue, + serializationQueue: serializationQueue, + eventMonitor: eventMonitor, + interceptor: interceptor, + fileManager: fileManager, + delegate: self) + + perform(request) + + return request + } + + // MARK: Perform + + /// Starts performing the provided `Request`. + /// + /// - Parameter request: The `Request` to perform. + func perform(_ request: Request) { + rootQueue.async { + guard !request.isCancelled else { return } + + self.activeRequests.insert(request) + + self.requestQueue.async { + // Leaf types must come first, otherwise they will cast as their superclass. + switch request { + case let r as UploadRequest: self.performUploadRequest(r) // UploadRequest must come before DataRequest due to subtype relationship. + case let r as DataRequest: self.performDataRequest(r) + case let r as DownloadRequest: self.performDownloadRequest(r) + case let r as DataStreamRequest: self.performDataStreamRequest(r) + default: fatalError("Attempted to perform unsupported Request subclass: \(type(of: request))") + } + } + } + } + + func performDataRequest(_ request: DataRequest) { + dispatchPrecondition(condition: .onQueue(requestQueue)) + + performSetupOperations(for: request, convertible: request.convertible) + } + + func performDataStreamRequest(_ request: DataStreamRequest) { + dispatchPrecondition(condition: .onQueue(requestQueue)) + + performSetupOperations(for: request, convertible: request.convertible) + } + + func performUploadRequest(_ request: UploadRequest) { + dispatchPrecondition(condition: .onQueue(requestQueue)) + + performSetupOperations(for: request, convertible: request.convertible) { + do { + let uploadable = try request.upload.createUploadable() + self.rootQueue.async { request.didCreateUploadable(uploadable) } + return true + } catch { + self.rootQueue.async { request.didFailToCreateUploadable(with: error.asAFError(or: .createUploadableFailed(error: error))) } + return false + } + } + } + + func performDownloadRequest(_ request: DownloadRequest) { + dispatchPrecondition(condition: .onQueue(requestQueue)) + + switch request.downloadable { + case let .request(convertible): + performSetupOperations(for: request, convertible: convertible) + case let .resumeData(resumeData): + rootQueue.async { self.didReceiveResumeData(resumeData, for: request) } + } + } + + func performSetupOperations(for request: Request, + convertible: URLRequestConvertible, + shouldCreateTask: @escaping () -> Bool = { true }) + { + dispatchPrecondition(condition: .onQueue(requestQueue)) + + let initialRequest: URLRequest + + do { + initialRequest = try convertible.asURLRequest() + try initialRequest.validate() + } catch { + rootQueue.async { request.didFailToCreateURLRequest(with: error.asAFError(or: .createURLRequestFailed(error: error))) } + return + } + + rootQueue.async { request.didCreateInitialURLRequest(initialRequest) } + + guard !request.isCancelled else { return } + + guard let adapter = adapter(for: request) else { + guard shouldCreateTask() else { return } + rootQueue.async { self.didCreateURLRequest(initialRequest, for: request) } + return + } + + let adapterState = RequestAdapterState(requestID: request.id, session: self) + + adapter.adapt(initialRequest, using: adapterState) { result in + do { + let adaptedRequest = try result.get() + try adaptedRequest.validate() + + self.rootQueue.async { request.didAdaptInitialRequest(initialRequest, to: adaptedRequest) } + + guard shouldCreateTask() else { return } + + self.rootQueue.async { self.didCreateURLRequest(adaptedRequest, for: request) } + } catch { + self.rootQueue.async { request.didFailToAdaptURLRequest(initialRequest, withError: .requestAdaptationFailed(error: error)) } + } + } + } + + // MARK: - Task Handling + + func didCreateURLRequest(_ urlRequest: URLRequest, for request: Request) { + dispatchPrecondition(condition: .onQueue(rootQueue)) + + request.didCreateURLRequest(urlRequest) + + guard !request.isCancelled else { return } + + let task = request.task(for: urlRequest, using: session) + requestTaskMap[request] = task + request.didCreateTask(task) + + updateStatesForTask(task, request: request) + } + + func didReceiveResumeData(_ data: Data, for request: DownloadRequest) { + dispatchPrecondition(condition: .onQueue(rootQueue)) + + guard !request.isCancelled else { return } + + let task = request.task(forResumeData: data, using: session) + requestTaskMap[request] = task + request.didCreateTask(task) + + updateStatesForTask(task, request: request) + } + + func updateStatesForTask(_ task: URLSessionTask, request: Request) { + dispatchPrecondition(condition: .onQueue(rootQueue)) + + request.withState { state in + switch state { + case .initialized, .finished: + // Do nothing. + break + case .resumed: + task.resume() + rootQueue.async { request.didResumeTask(task) } + case .suspended: + task.suspend() + rootQueue.async { request.didSuspendTask(task) } + case .cancelled: + // Resume to ensure metrics are gathered. + task.resume() + task.cancel() + rootQueue.async { request.didCancelTask(task) } + } + } + } + + // MARK: - Adapters and Retriers + + func adapter(for request: Request) -> RequestAdapter? { + if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor { + return Interceptor(adapters: [requestInterceptor, sessionInterceptor]) + } else { + return request.interceptor ?? interceptor + } + } + + func retrier(for request: Request) -> RequestRetrier? { + if let requestInterceptor = request.interceptor, let sessionInterceptor = interceptor { + return Interceptor(retriers: [requestInterceptor, sessionInterceptor]) + } else { + return request.interceptor ?? interceptor + } + } + + // MARK: - Invalidation + + func finishRequestsForDeinit() { + requestTaskMap.requests.forEach { request in + rootQueue.async { + request.finish(error: AFError.sessionDeinitialized) + } + } + } +} + +// MARK: - RequestDelegate + +extension Session: RequestDelegate { + public var sessionConfiguration: URLSessionConfiguration { + session.configuration + } + + public var startImmediately: Bool { startRequestsImmediately } + + public func cleanup(after request: Request) { + activeRequests.remove(request) + } + + public func retryResult(for request: Request, dueTo error: AFError, completion: @escaping (RetryResult) -> Void) { + guard let retrier = retrier(for: request) else { + rootQueue.async { completion(.doNotRetry) } + return + } + + retrier.retry(request, for: self, dueTo: error) { retryResult in + self.rootQueue.async { + guard let retryResultError = retryResult.error else { completion(retryResult); return } + + let retryError = AFError.requestRetryFailed(retryError: retryResultError, originalError: error) + completion(.doNotRetryWithError(retryError)) + } + } + } + + public func retryRequest(_ request: Request, withDelay timeDelay: TimeInterval?) { + rootQueue.async { + let retry: () -> Void = { + guard !request.isCancelled else { return } + + request.prepareForRetry() + self.perform(request) + } + + if let retryDelay = timeDelay { + self.rootQueue.after(retryDelay) { retry() } + } else { + retry() + } + } + } +} + +// MARK: - SessionStateProvider + +extension Session: SessionStateProvider { + func request(for task: URLSessionTask) -> Request? { + dispatchPrecondition(condition: .onQueue(rootQueue)) + + return requestTaskMap[task] + } + + func didGatherMetricsForTask(_ task: URLSessionTask) { + dispatchPrecondition(condition: .onQueue(rootQueue)) + + let didDisassociate = requestTaskMap.disassociateIfNecessaryAfterGatheringMetricsForTask(task) + + if didDisassociate { + waitingCompletions[task]?() + waitingCompletions[task] = nil + } + } + + func didCompleteTask(_ task: URLSessionTask, completion: @escaping () -> Void) { + dispatchPrecondition(condition: .onQueue(rootQueue)) + + let didDisassociate = requestTaskMap.disassociateIfNecessaryAfterCompletingTask(task) + + if didDisassociate { + completion() + } else { + waitingCompletions[task] = completion + } + } + + func credential(for task: URLSessionTask, in protectionSpace: URLProtectionSpace) -> URLCredential? { + dispatchPrecondition(condition: .onQueue(rootQueue)) + + return requestTaskMap[task]?.credential ?? + session.configuration.urlCredentialStorage?.defaultCredential(for: protectionSpace) + } + + func cancelRequestsForSessionInvalidation(with error: Error?) { + dispatchPrecondition(condition: .onQueue(rootQueue)) + + requestTaskMap.requests.forEach { $0.finish(error: AFError.sessionInvalidated(error: error)) } + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/SessionDelegate.swift b/Instagram-Clone/Pods/Alamofire/Source/SessionDelegate.swift new file mode 100644 index 0000000..a794d83 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/SessionDelegate.swift @@ -0,0 +1,336 @@ +// +// SessionDelegate.swift +// +// Copyright (c) 2014-2018 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 + +/// Class which implements the various `URLSessionDelegate` methods to connect various Alamofire features. +open class SessionDelegate: NSObject { + private let fileManager: FileManager + + weak var stateProvider: SessionStateProvider? + var eventMonitor: EventMonitor? + + /// Creates an instance from the given `FileManager`. + /// + /// - Parameter fileManager: `FileManager` to use for underlying file management, such as moving downloaded files. + /// `.default` by default. + public init(fileManager: FileManager = .default) { + self.fileManager = fileManager + } + + /// Internal method to find and cast requests while maintaining some integrity checking. + /// + /// - Parameters: + /// - task: The `URLSessionTask` for which to find the associated `Request`. + /// - type: The `Request` subclass type to cast any `Request` associate with `task`. + func request(for task: URLSessionTask, as type: R.Type) -> R? { + guard let provider = stateProvider else { + assertionFailure("StateProvider is nil.") + return nil + } + + return provider.request(for: task) as? R + } +} + +/// Type which provides various `Session` state values. +protocol SessionStateProvider: AnyObject { + var serverTrustManager: ServerTrustManager? { get } + var redirectHandler: RedirectHandler? { get } + var cachedResponseHandler: CachedResponseHandler? { get } + + func request(for task: URLSessionTask) -> Request? + func didGatherMetricsForTask(_ task: URLSessionTask) + func didCompleteTask(_ task: URLSessionTask, completion: @escaping () -> Void) + func credential(for task: URLSessionTask, in protectionSpace: URLProtectionSpace) -> URLCredential? + func cancelRequestsForSessionInvalidation(with error: Error?) +} + +// MARK: URLSessionDelegate + +extension SessionDelegate: URLSessionDelegate { + open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) { + eventMonitor?.urlSession(session, didBecomeInvalidWithError: error) + + stateProvider?.cancelRequestsForSessionInvalidation(with: error) + } +} + +// MARK: URLSessionTaskDelegate + +extension SessionDelegate: URLSessionTaskDelegate { + /// Result of a `URLAuthenticationChallenge` evaluation. + typealias ChallengeEvaluation = (disposition: URLSession.AuthChallengeDisposition, credential: URLCredential?, error: AFError?) + + open func urlSession(_ session: URLSession, + task: URLSessionTask, + didReceive challenge: URLAuthenticationChallenge, + completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { + eventMonitor?.urlSession(session, task: task, didReceive: challenge) + + let evaluation: ChallengeEvaluation + switch challenge.protectionSpace.authenticationMethod { + case NSURLAuthenticationMethodHTTPBasic, NSURLAuthenticationMethodHTTPDigest, NSURLAuthenticationMethodNTLM, + NSURLAuthenticationMethodNegotiate: + evaluation = attemptCredentialAuthentication(for: challenge, belongingTo: task) + #if !(os(Linux) || os(Windows)) + case NSURLAuthenticationMethodServerTrust: + evaluation = attemptServerTrustAuthentication(with: challenge) + case NSURLAuthenticationMethodClientCertificate: + evaluation = attemptCredentialAuthentication(for: challenge, belongingTo: task) + #endif + default: + evaluation = (.performDefaultHandling, nil, nil) + } + + if let error = evaluation.error { + stateProvider?.request(for: task)?.didFailTask(task, earlyWithError: error) + } + + completionHandler(evaluation.disposition, evaluation.credential) + } + + #if !(os(Linux) || os(Windows)) + /// Evaluates the server trust `URLAuthenticationChallenge` received. + /// + /// - Parameter challenge: The `URLAuthenticationChallenge`. + /// + /// - Returns: The `ChallengeEvaluation`. + func attemptServerTrustAuthentication(with challenge: URLAuthenticationChallenge) -> ChallengeEvaluation { + let host = challenge.protectionSpace.host + + guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust, + let trust = challenge.protectionSpace.serverTrust + else { + return (.performDefaultHandling, nil, nil) + } + + do { + guard let evaluator = try stateProvider?.serverTrustManager?.serverTrustEvaluator(forHost: host) else { + return (.performDefaultHandling, nil, nil) + } + + try evaluator.evaluate(trust, forHost: host) + + return (.useCredential, URLCredential(trust: trust), nil) + } catch { + return (.cancelAuthenticationChallenge, nil, error.asAFError(or: .serverTrustEvaluationFailed(reason: .customEvaluationFailed(error: error)))) + } + } + #endif + + /// Evaluates the credential-based authentication `URLAuthenticationChallenge` received for `task`. + /// + /// - Parameters: + /// - challenge: The `URLAuthenticationChallenge`. + /// - task: The `URLSessionTask` which received the challenge. + /// + /// - Returns: The `ChallengeEvaluation`. + func attemptCredentialAuthentication(for challenge: URLAuthenticationChallenge, + belongingTo task: URLSessionTask) -> ChallengeEvaluation { + guard challenge.previousFailureCount == 0 else { + return (.rejectProtectionSpace, nil, nil) + } + + guard let credential = stateProvider?.credential(for: task, in: challenge.protectionSpace) else { + return (.performDefaultHandling, nil, nil) + } + + return (.useCredential, credential, nil) + } + + open func urlSession(_ session: URLSession, + task: URLSessionTask, + didSendBodyData bytesSent: Int64, + totalBytesSent: Int64, + totalBytesExpectedToSend: Int64) { + eventMonitor?.urlSession(session, + task: task, + didSendBodyData: bytesSent, + totalBytesSent: totalBytesSent, + totalBytesExpectedToSend: totalBytesExpectedToSend) + + stateProvider?.request(for: task)?.updateUploadProgress(totalBytesSent: totalBytesSent, + totalBytesExpectedToSend: totalBytesExpectedToSend) + } + + open func urlSession(_ session: URLSession, + task: URLSessionTask, + needNewBodyStream completionHandler: @escaping (InputStream?) -> Void) { + eventMonitor?.urlSession(session, taskNeedsNewBodyStream: task) + + guard let request = request(for: task, as: UploadRequest.self) else { + assertionFailure("needNewBodyStream did not find UploadRequest.") + completionHandler(nil) + return + } + + completionHandler(request.inputStream()) + } + + open func urlSession(_ session: URLSession, + task: URLSessionTask, + willPerformHTTPRedirection response: HTTPURLResponse, + newRequest request: URLRequest, + completionHandler: @escaping (URLRequest?) -> Void) { + eventMonitor?.urlSession(session, task: task, willPerformHTTPRedirection: response, newRequest: request) + + if let redirectHandler = stateProvider?.request(for: task)?.redirectHandler ?? stateProvider?.redirectHandler { + redirectHandler.task(task, willBeRedirectedTo: request, for: response, completion: completionHandler) + } else { + completionHandler(request) + } + } + + open func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) { + eventMonitor?.urlSession(session, task: task, didFinishCollecting: metrics) + + stateProvider?.request(for: task)?.didGatherMetrics(metrics) + + stateProvider?.didGatherMetricsForTask(task) + } + + open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { + eventMonitor?.urlSession(session, task: task, didCompleteWithError: error) + + let request = stateProvider?.request(for: task) + + stateProvider?.didCompleteTask(task) { + request?.didCompleteTask(task, with: error.map { $0.asAFError(or: .sessionTaskFailed(error: $0)) }) + } + } + + @available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) + open func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) { + eventMonitor?.urlSession(session, taskIsWaitingForConnectivity: task) + } +} + +// MARK: URLSessionDataDelegate + +extension SessionDelegate: URLSessionDataDelegate { + open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { + eventMonitor?.urlSession(session, dataTask: dataTask, didReceive: data) + + if let request = request(for: dataTask, as: DataRequest.self) { + request.didReceive(data: data) + } else if let request = request(for: dataTask, as: DataStreamRequest.self) { + request.didReceive(data: data) + } else { + assertionFailure("dataTask did not find DataRequest or DataStreamRequest in didReceive") + return + } + } + + open func urlSession(_ session: URLSession, + dataTask: URLSessionDataTask, + willCacheResponse proposedResponse: CachedURLResponse, + completionHandler: @escaping (CachedURLResponse?) -> Void) { + eventMonitor?.urlSession(session, dataTask: dataTask, willCacheResponse: proposedResponse) + + if let handler = stateProvider?.request(for: dataTask)?.cachedResponseHandler ?? stateProvider?.cachedResponseHandler { + handler.dataTask(dataTask, willCacheResponse: proposedResponse, completion: completionHandler) + } else { + completionHandler(proposedResponse) + } + } +} + +// MARK: URLSessionDownloadDelegate + +extension SessionDelegate: URLSessionDownloadDelegate { + open func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didResumeAtOffset fileOffset: Int64, + expectedTotalBytes: Int64) { + eventMonitor?.urlSession(session, + downloadTask: downloadTask, + didResumeAtOffset: fileOffset, + expectedTotalBytes: expectedTotalBytes) + guard let downloadRequest = request(for: downloadTask, as: DownloadRequest.self) else { + assertionFailure("downloadTask did not find DownloadRequest.") + return + } + + downloadRequest.updateDownloadProgress(bytesWritten: fileOffset, + totalBytesExpectedToWrite: expectedTotalBytes) + } + + open func urlSession(_ session: URLSession, + downloadTask: URLSessionDownloadTask, + didWriteData bytesWritten: Int64, + totalBytesWritten: Int64, + totalBytesExpectedToWrite: Int64) { + eventMonitor?.urlSession(session, + downloadTask: downloadTask, + didWriteData: bytesWritten, + totalBytesWritten: totalBytesWritten, + totalBytesExpectedToWrite: totalBytesExpectedToWrite) + guard let downloadRequest = request(for: downloadTask, as: DownloadRequest.self) else { + assertionFailure("downloadTask did not find DownloadRequest.") + return + } + + downloadRequest.updateDownloadProgress(bytesWritten: bytesWritten, + totalBytesExpectedToWrite: totalBytesExpectedToWrite) + } + + open func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { + eventMonitor?.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location) + + guard let request = request(for: downloadTask, as: DownloadRequest.self) else { + assertionFailure("downloadTask did not find DownloadRequest.") + return + } + + let (destination, options): (URL, DownloadRequest.Options) + if let response = request.response { + (destination, options) = request.destination(location, response) + } else { + // If there's no response this is likely a local file download, so generate the temporary URL directly. + (destination, options) = (DownloadRequest.defaultDestinationURL(location), []) + } + + eventMonitor?.request(request, didCreateDestinationURL: destination) + + do { + if options.contains(.removePreviousFile), fileManager.fileExists(atPath: destination.path) { + try fileManager.removeItem(at: destination) + } + + if options.contains(.createIntermediateDirectories) { + let directory = destination.deletingLastPathComponent() + try fileManager.createDirectory(at: directory, withIntermediateDirectories: true) + } + + try fileManager.moveItem(at: location, to: destination) + + request.didFinishDownloading(using: downloadTask, with: .success(destination)) + } catch { + request.didFinishDownloading(using: downloadTask, with: .failure(.downloadedFileMoveFailed(error: error, + source: location, + destination: destination))) + } + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/StringEncoding+Alamofire.swift b/Instagram-Clone/Pods/Alamofire/Source/StringEncoding+Alamofire.swift new file mode 100644 index 0000000..8fa6133 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/StringEncoding+Alamofire.swift @@ -0,0 +1,55 @@ +// +// StringEncoding+Alamofire.swift +// +// Copyright (c) 2020 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 String.Encoding { + /// Creates an encoding from the IANA charset name. + /// + /// - Notes: These mappings match those [provided by CoreFoundation](https://opensource.apple.com/source/CF/CF-476.18/CFStringUtilities.c.auto.html) + /// + /// - Parameter name: IANA charset name. + init?(ianaCharsetName name: String) { + switch name.lowercased() { + case "utf-8": + self = .utf8 + case "iso-8859-1": + self = .isoLatin1 + case "unicode-1-1", "iso-10646-ucs-2", "utf-16": + self = .utf16 + case "utf-16be": + self = .utf16BigEndian + case "utf-16le": + self = .utf16LittleEndian + case "utf-32": + self = .utf32 + case "utf-32be": + self = .utf32BigEndian + case "utf-32le": + self = .utf32LittleEndian + default: + return nil + } + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/URLConvertible+URLRequestConvertible.swift b/Instagram-Clone/Pods/Alamofire/Source/URLConvertible+URLRequestConvertible.swift new file mode 100644 index 0000000..455c4bc --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/URLConvertible+URLRequestConvertible.swift @@ -0,0 +1,105 @@ +// +// URLConvertible+URLRequestConvertible.swift +// +// Copyright (c) 2014-2018 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 `URL`s, which can then be used to construct +/// `URLRequests`. +public protocol URLConvertible { + /// Returns a `URL` from the conforming instance or throws. + /// + /// - Returns: The `URL` created from the instance. + /// - Throws: Any error thrown while creating the `URL`. + func asURL() throws -> URL +} + +extension String: URLConvertible { + /// Returns a `URL` if `self` can be used to initialize a `URL` instance, otherwise throws. + /// + /// - Returns: The `URL` initialized with `self`. + /// - Throws: An `AFError.invalidURL` instance. + 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 { self } +} + +extension URLComponents: URLConvertible { + /// Returns a `URL` if the `self`'s `url` is not nil, otherwise throws. + /// + /// - Returns: The `URL` from the `url` property. + /// - Throws: An `AFError.invalidURL` instance. + 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 safely construct `URLRequest`s. +public protocol URLRequestConvertible { + /// Returns a `URLRequest` or throws if an `Error` was encountered. + /// + /// - Returns: A `URLRequest`. + /// - Throws: Any error thrown while constructing the `URLRequest`. + func asURLRequest() throws -> URLRequest +} + +extension URLRequestConvertible { + /// The `URLRequest` returned by discarding any `Error` encountered. + public var urlRequest: URLRequest? { try? asURLRequest() } +} + +extension URLRequest: URLRequestConvertible { + /// Returns `self`. + public func asURLRequest() throws -> URLRequest { self } +} + +// MARK: - + +extension URLRequest { + /// Creates an instance with the specified `url`, `method`, and `headers`. + /// + /// - Parameters: + /// - url: The `URLConvertible` value. + /// - method: The `HTTPMethod`. + /// - headers: The `HTTPHeaders`, `nil` by default. + /// - Throws: Any error thrown while converting the `URLConvertible` to a `URL`. + public init(url: URLConvertible, method: HTTPMethod, headers: HTTPHeaders? = nil) throws { + let url = try url.asURL() + + self.init(url: url) + + httpMethod = method.rawValue + allHTTPHeaderFields = headers?.dictionary + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/URLEncodedFormEncoder.swift b/Instagram-Clone/Pods/Alamofire/Source/URLEncodedFormEncoder.swift new file mode 100644 index 0000000..dfadc2e --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/URLEncodedFormEncoder.swift @@ -0,0 +1,982 @@ +// +// URLEncodedFormEncoder.swift +// +// Copyright (c) 2019 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 + +/// An object that encodes instances into URL-encoded query strings. +/// +/// 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 `Bool` values are encoded. The default behavior is to encode +/// `true` as 1 and `false` as 0. +/// +/// `DateEncoding` can be used to configure how `Date` values are encoded. By default, the `.deferredToDate` +/// strategy is used, which formats dates from their structure. +/// +/// `SpaceEncoding` can be used to configure how spaces are encoded. Modern encodings use percent replacement (`%20`), +/// while older encodings may expect spaces to be replaced with `+`. +/// +/// This type is largely based on Vapor's [`url-encoded-form`](https://github.com/vapor/url-encoded-form) project. +public final class URLEncodedFormEncoder { + /// Encoding to use for `Array` values. + public enum ArrayEncoding { + /// An empty set of square brackets ("[]") are appended to the key for every value. This is the default encoding. + case brackets + /// No brackets are appended to the key and the key is encoded as is. + case noBrackets + /// Brackets containing the item index are appended. This matches the jQuery and Node.js behavior. + case indexInBrackets + + /// Encodes the key according to the encoding. + /// + /// - Parameters: + /// - key: The `key` to encode. + /// - index: When this enum instance is `.indexInBrackets`, the `index` to encode. + /// + /// - Returns: The encoded key. + func encode(_ key: String, atIndex index: Int) -> String { + switch self { + case .brackets: return "\(key)[]" + case .noBrackets: return key + case .indexInBrackets: return "\(key)[\(index)]" + } + } + } + + /// Encoding to use for `Bool` values. + public enum BoolEncoding { + /// Encodes `true` as `1`, `false` as `0`. + case numeric + /// Encodes `true` as "true", `false` as "false". This is the default encoding. + case literal + + /// Encodes the given `Bool` as a `String`. + /// + /// - Parameter value: The `Bool` to encode. + /// + /// - Returns: The encoded `String`. + func encode(_ value: Bool) -> String { + switch self { + case .numeric: return value ? "1" : "0" + case .literal: return value ? "true" : "false" + } + } + } + + /// Encoding to use for `Data` values. + public enum DataEncoding { + /// Defers encoding to the `Data` type. + case deferredToData + /// Encodes `Data` as a Base64-encoded string. This is the default encoding. + case base64 + /// Encode the `Data` as a custom value encoded by the given closure. + case custom((Data) throws -> String) + + /// Encodes `Data` according to the encoding. + /// + /// - Parameter data: The `Data` to encode. + /// + /// - Returns: The encoded `String`, or `nil` if the `Data` should be encoded according to its + /// `Encodable` implementation. + func encode(_ data: Data) throws -> String? { + switch self { + case .deferredToData: return nil + case .base64: return data.base64EncodedString() + case let .custom(encoding): return try encoding(data) + } + } + } + + /// Encoding to use for `Date` values. + public enum DateEncoding { + /// ISO8601 and RFC3339 formatter. + private static let iso8601Formatter: ISO8601DateFormatter = { + let formatter = ISO8601DateFormatter() + formatter.formatOptions = .withInternetDateTime + return formatter + }() + + /// Defers encoding to the `Date` type. This is the default encoding. + case deferredToDate + /// Encodes `Date`s as seconds since midnight UTC on January 1, 1970. + case secondsSince1970 + /// Encodes `Date`s as milliseconds since midnight UTC on January 1, 1970. + case millisecondsSince1970 + /// Encodes `Date`s according to the ISO8601 and RFC3339 standards. + case iso8601 + /// Encodes `Date`s using the given `DateFormatter`. + case formatted(DateFormatter) + /// Encodes `Date`s using the given closure. + case custom((Date) throws -> String) + + /// Encodes the date according to the encoding. + /// + /// - Parameter date: The `Date` to encode. + /// + /// - Returns: The encoded `String`, or `nil` if the `Date` should be encoded according to its + /// `Encodable` implementation. + func encode(_ date: Date) throws -> String? { + switch self { + case .deferredToDate: + return nil + case .secondsSince1970: + return String(date.timeIntervalSince1970) + case .millisecondsSince1970: + return String(date.timeIntervalSince1970 * 1000.0) + case .iso8601: + return DateEncoding.iso8601Formatter.string(from: date) + case let .formatted(formatter): + return formatter.string(from: date) + case let .custom(closure): + return try closure(date) + } + } + } + + /// Encoding to use for keys. + /// + /// This type is derived from [`JSONEncoder`'s `KeyEncodingStrategy`](https://github.com/apple/swift/blob/6aa313b8dd5f05135f7f878eccc1db6f9fbe34ff/stdlib/public/Darwin/Foundation/JSONEncoder.swift#L128) + /// and [`XMLEncoder`s `KeyEncodingStrategy`](https://github.com/MaxDesiatov/XMLCoder/blob/master/Sources/XMLCoder/Encoder/XMLEncoder.swift#L102). + public enum KeyEncoding { + /// Use the keys specified by each type. This is the default encoding. + case useDefaultKeys + /// Convert from "camelCaseKeys" to "snake_case_keys" before writing a key. + /// + /// Capital characters are determined by testing membership in + /// `CharacterSet.uppercaseLetters` and `CharacterSet.lowercaseLetters` + /// (Unicode General Categories Lu and Lt). + /// The conversion to lower case uses `Locale.system`, also known as + /// the ICU "root" locale. This means the result is consistent + /// regardless of the current user's locale and language preferences. + /// + /// Converting from camel case to snake case: + /// 1. Splits words at the boundary of lower-case to upper-case + /// 2. Inserts `_` between words + /// 3. Lowercases the entire string + /// 4. Preserves starting and ending `_`. + /// + /// For example, `oneTwoThree` becomes `one_two_three`. `_oneTwoThree_` becomes `_one_two_three_`. + /// + /// - Note: Using a key encoding strategy has a nominal performance cost, as each string key has to be converted. + case convertToSnakeCase + /// Same as convertToSnakeCase, but using `-` instead of `_`. + /// For example `oneTwoThree` becomes `one-two-three`. + case convertToKebabCase + /// Capitalize the first letter only. + /// For example `oneTwoThree` becomes `OneTwoThree`. + case capitalized + /// Uppercase all letters. + /// For example `oneTwoThree` becomes `ONETWOTHREE`. + case uppercased + /// Lowercase all letters. + /// For example `oneTwoThree` becomes `onetwothree`. + case lowercased + /// A custom encoding using the provided closure. + case custom((String) -> String) + + func encode(_ key: String) -> String { + switch self { + case .useDefaultKeys: return key + case .convertToSnakeCase: return convertToSnakeCase(key) + case .convertToKebabCase: return convertToKebabCase(key) + case .capitalized: return String(key.prefix(1).uppercased() + key.dropFirst()) + case .uppercased: return key.uppercased() + case .lowercased: return key.lowercased() + case let .custom(encoding): return encoding(key) + } + } + + private func convertToSnakeCase(_ key: String) -> String { + convert(key, usingSeparator: "_") + } + + private func convertToKebabCase(_ key: String) -> String { + convert(key, usingSeparator: "-") + } + + private func convert(_ key: String, usingSeparator separator: String) -> String { + guard !key.isEmpty else { return key } + + var words: [Range] = [] + // The general idea of this algorithm is to split words on + // transition from lower to upper case, then on transition of >1 + // upper case characters to lowercase + // + // myProperty -> my_property + // myURLProperty -> my_url_property + // + // It is assumed, per Swift naming conventions, that the first character of the key is lowercase. + var wordStart = key.startIndex + var searchRange = key.index(after: wordStart)..1 capital letters. Turn those into a word, stopping at the capital before the lower case character. + let beforeLowerIndex = key.index(before: lowerCaseRange.lowerBound) + words.append(upperCaseRange.lowerBound.. String { + switch self { + case .percentEscaped: return string.replacingOccurrences(of: " ", with: "%20") + case .plusReplaced: return string.replacingOccurrences(of: " ", with: "+") + } + } + } + + /// `URLEncodedFormEncoder` error. + public enum Error: Swift.Error { + /// An invalid root object was created by the encoder. Only keyed values are valid. + case invalidRootObject(String) + + var localizedDescription: String { + switch self { + case let .invalidRootObject(object): + return "URLEncodedFormEncoder requires keyed root object. Received \(object) instead." + } + } + } + + /// Whether or not to sort the encoded key value pairs. + /// + /// - Note: This setting ensures a consistent ordering for all encodings of the same parameters. When set to `false`, + /// encoded `Dictionary` values may have a different encoded order each time they're encoded due to + /// ` Dictionary`'s random storage order, but `Encodable` types will maintain their encoded order. + public let alphabetizeKeyValuePairs: Bool + /// The `ArrayEncoding` to use. + public let arrayEncoding: ArrayEncoding + /// The `BoolEncoding` to use. + public let boolEncoding: BoolEncoding + /// THe `DataEncoding` to use. + public let dataEncoding: DataEncoding + /// The `DateEncoding` to use. + public let dateEncoding: DateEncoding + /// The `KeyEncoding` to use. + public let keyEncoding: KeyEncoding + /// The `SpaceEncoding` to use. + public let spaceEncoding: SpaceEncoding + /// The `CharacterSet` of allowed (non-escaped) characters. + public var allowedCharacters: CharacterSet + + /// Creates an instance from the supplied parameters. + /// + /// - Parameters: + /// - alphabetizeKeyValuePairs: Whether or not to sort the encoded key value pairs. `true` by default. + /// - arrayEncoding: The `ArrayEncoding` to use. `.brackets` by default. + /// - boolEncoding: The `BoolEncoding` to use. `.numeric` by default. + /// - dataEncoding: The `DataEncoding` to use. `.base64` by default. + /// - dateEncoding: The `DateEncoding` to use. `.deferredToDate` by default. + /// - keyEncoding: The `KeyEncoding` to use. `.useDefaultKeys` by default. + /// - spaceEncoding: The `SpaceEncoding` to use. `.percentEscaped` by default. + /// - allowedCharacters: The `CharacterSet` of allowed (non-escaped) characters. `.afURLQueryAllowed` by + /// default. + public init(alphabetizeKeyValuePairs: Bool = true, + arrayEncoding: ArrayEncoding = .brackets, + boolEncoding: BoolEncoding = .numeric, + dataEncoding: DataEncoding = .base64, + dateEncoding: DateEncoding = .deferredToDate, + keyEncoding: KeyEncoding = .useDefaultKeys, + spaceEncoding: SpaceEncoding = .percentEscaped, + allowedCharacters: CharacterSet = .afURLQueryAllowed) { + self.alphabetizeKeyValuePairs = alphabetizeKeyValuePairs + self.arrayEncoding = arrayEncoding + self.boolEncoding = boolEncoding + self.dataEncoding = dataEncoding + self.dateEncoding = dateEncoding + self.keyEncoding = keyEncoding + self.spaceEncoding = spaceEncoding + self.allowedCharacters = allowedCharacters + } + + func encode(_ value: Encodable) throws -> URLEncodedFormComponent { + let context = URLEncodedFormContext(.object([])) + let encoder = _URLEncodedFormEncoder(context: context, + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + try value.encode(to: encoder) + + return context.component + } + + /// Encodes the `value` as a URL form encoded `String`. + /// + /// - Parameter value: The `Encodable` value.` + /// + /// - Returns: The encoded `String`. + /// - Throws: An `Error` or `EncodingError` instance if encoding fails. + public func encode(_ value: Encodable) throws -> String { + let component: URLEncodedFormComponent = try encode(value) + + guard case let .object(object) = component else { + throw Error.invalidRootObject("\(component)") + } + + let serializer = URLEncodedFormSerializer(alphabetizeKeyValuePairs: alphabetizeKeyValuePairs, + arrayEncoding: arrayEncoding, + keyEncoding: keyEncoding, + spaceEncoding: spaceEncoding, + allowedCharacters: allowedCharacters) + let query = serializer.serialize(object) + + return query + } + + /// Encodes the value as `Data`. This is performed by first creating an encoded `String` and then returning the + /// `.utf8` data. + /// + /// - Parameter value: The `Encodable` value. + /// + /// - Returns: The encoded `Data`. + /// + /// - Throws: An `Error` or `EncodingError` instance if encoding fails. + public func encode(_ value: Encodable) throws -> Data { + let string: String = try encode(value) + + return Data(string.utf8) + } +} + +final class _URLEncodedFormEncoder { + var codingPath: [CodingKey] + // Returns an empty dictionary, as this encoder doesn't support userInfo. + var userInfo: [CodingUserInfoKey: Any] { [:] } + + let context: URLEncodedFormContext + + private let boolEncoding: URLEncodedFormEncoder.BoolEncoding + private let dataEncoding: URLEncodedFormEncoder.DataEncoding + private let dateEncoding: URLEncodedFormEncoder.DateEncoding + + init(context: URLEncodedFormContext, + codingPath: [CodingKey] = [], + boolEncoding: URLEncodedFormEncoder.BoolEncoding, + dataEncoding: URLEncodedFormEncoder.DataEncoding, + dateEncoding: URLEncodedFormEncoder.DateEncoding) { + self.context = context + self.codingPath = codingPath + self.boolEncoding = boolEncoding + self.dataEncoding = dataEncoding + self.dateEncoding = dateEncoding + } +} + +extension _URLEncodedFormEncoder: Encoder { + func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { + let container = _URLEncodedFormEncoder.KeyedContainer(context: context, + codingPath: codingPath, + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + return KeyedEncodingContainer(container) + } + + func unkeyedContainer() -> UnkeyedEncodingContainer { + _URLEncodedFormEncoder.UnkeyedContainer(context: context, + codingPath: codingPath, + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + } + + func singleValueContainer() -> SingleValueEncodingContainer { + _URLEncodedFormEncoder.SingleValueContainer(context: context, + codingPath: codingPath, + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + } +} + +final class URLEncodedFormContext { + var component: URLEncodedFormComponent + + init(_ component: URLEncodedFormComponent) { + self.component = component + } +} + +enum URLEncodedFormComponent { + typealias Object = [(key: String, value: URLEncodedFormComponent)] + + case string(String) + case array([URLEncodedFormComponent]) + case object(Object) + + /// Converts self to an `[URLEncodedFormData]` or returns `nil` if not convertible. + var array: [URLEncodedFormComponent]? { + switch self { + case let .array(array): return array + default: return nil + } + } + + /// Converts self to an `Object` or returns `nil` if not convertible. + var object: Object? { + switch self { + case let .object(object): return object + default: return nil + } + } + + /// Sets self to the supplied value at a given path. + /// + /// data.set(to: "hello", at: ["path", "to", "value"]) + /// + /// - parameters: + /// - value: Value of `Self` to set at the supplied path. + /// - path: `CodingKey` path to update with the supplied value. + public mutating func set(to value: URLEncodedFormComponent, at path: [CodingKey]) { + set(&self, to: value, at: path) + } + + /// Recursive backing method to `set(to:at:)`. + private func set(_ context: inout URLEncodedFormComponent, to value: URLEncodedFormComponent, at path: [CodingKey]) { + guard !path.isEmpty else { + context = value + return + } + + let end = path[0] + var child: URLEncodedFormComponent + switch path.count { + case 1: + child = value + case 2...: + if let index = end.intValue { + let array = context.array ?? [] + if array.count > index { + child = array[index] + } else { + child = .array([]) + } + set(&child, to: value, at: Array(path[1...])) + } else { + child = context.object?.first { $0.key == end.stringValue }?.value ?? .object(.init()) + set(&child, to: value, at: Array(path[1...])) + } + default: fatalError("Unreachable") + } + + if let index = end.intValue { + if var array = context.array { + if array.count > index { + array[index] = child + } else { + array.append(child) + } + context = .array(array) + } else { + context = .array([child]) + } + } else { + if var object = context.object { + if let index = object.firstIndex(where: { $0.key == end.stringValue }) { + object[index] = (key: end.stringValue, value: child) + } else { + object.append((key: end.stringValue, value: child)) + } + context = .object(object) + } else { + context = .object([(key: end.stringValue, value: child)]) + } + } + } +} + +struct AnyCodingKey: CodingKey, Hashable { + let stringValue: String + let intValue: Int? + + init?(stringValue: String) { + self.stringValue = stringValue + intValue = nil + } + + init?(intValue: Int) { + stringValue = "\(intValue)" + self.intValue = intValue + } + + init(_ base: Key) where Key: CodingKey { + if let intValue = base.intValue { + self.init(intValue: intValue)! + } else { + self.init(stringValue: base.stringValue)! + } + } +} + +extension _URLEncodedFormEncoder { + final class KeyedContainer where Key: CodingKey { + var codingPath: [CodingKey] + + private let context: URLEncodedFormContext + private let boolEncoding: URLEncodedFormEncoder.BoolEncoding + private let dataEncoding: URLEncodedFormEncoder.DataEncoding + private let dateEncoding: URLEncodedFormEncoder.DateEncoding + + init(context: URLEncodedFormContext, + codingPath: [CodingKey], + boolEncoding: URLEncodedFormEncoder.BoolEncoding, + dataEncoding: URLEncodedFormEncoder.DataEncoding, + dateEncoding: URLEncodedFormEncoder.DateEncoding) { + self.context = context + self.codingPath = codingPath + self.boolEncoding = boolEncoding + self.dataEncoding = dataEncoding + self.dateEncoding = dateEncoding + } + + private func nestedCodingPath(for key: CodingKey) -> [CodingKey] { + codingPath + [key] + } + } +} + +extension _URLEncodedFormEncoder.KeyedContainer: KeyedEncodingContainerProtocol { + func encodeNil(forKey key: Key) throws { + let context = EncodingError.Context(codingPath: codingPath, + debugDescription: "URLEncodedFormEncoder cannot encode nil values.") + throw EncodingError.invalidValue("\(key): nil", context) + } + + func encode(_ value: T, forKey key: Key) throws where T: Encodable { + var container = nestedSingleValueEncoder(for: key) + try container.encode(value) + } + + func nestedSingleValueEncoder(for key: Key) -> SingleValueEncodingContainer { + let container = _URLEncodedFormEncoder.SingleValueContainer(context: context, + codingPath: nestedCodingPath(for: key), + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + + return container + } + + func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { + let container = _URLEncodedFormEncoder.UnkeyedContainer(context: context, + codingPath: nestedCodingPath(for: key), + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + + return container + } + + func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer where NestedKey: CodingKey { + let container = _URLEncodedFormEncoder.KeyedContainer(context: context, + codingPath: nestedCodingPath(for: key), + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + + return KeyedEncodingContainer(container) + } + + func superEncoder() -> Encoder { + _URLEncodedFormEncoder(context: context, + codingPath: codingPath, + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + } + + func superEncoder(forKey key: Key) -> Encoder { + _URLEncodedFormEncoder(context: context, + codingPath: nestedCodingPath(for: key), + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + } +} + +extension _URLEncodedFormEncoder { + final class SingleValueContainer { + var codingPath: [CodingKey] + + private var canEncodeNewValue = true + + private let context: URLEncodedFormContext + private let boolEncoding: URLEncodedFormEncoder.BoolEncoding + private let dataEncoding: URLEncodedFormEncoder.DataEncoding + private let dateEncoding: URLEncodedFormEncoder.DateEncoding + + init(context: URLEncodedFormContext, + codingPath: [CodingKey], + boolEncoding: URLEncodedFormEncoder.BoolEncoding, + dataEncoding: URLEncodedFormEncoder.DataEncoding, + dateEncoding: URLEncodedFormEncoder.DateEncoding) { + self.context = context + self.codingPath = codingPath + self.boolEncoding = boolEncoding + self.dataEncoding = dataEncoding + self.dateEncoding = dateEncoding + } + + private func checkCanEncode(value: Any?) throws { + guard canEncodeNewValue else { + let context = EncodingError.Context(codingPath: codingPath, + debugDescription: "Attempt to encode value through single value container when previously value already encoded.") + throw EncodingError.invalidValue(value as Any, context) + } + } + } +} + +extension _URLEncodedFormEncoder.SingleValueContainer: SingleValueEncodingContainer { + func encodeNil() throws { + try checkCanEncode(value: nil) + defer { canEncodeNewValue = false } + + let context = EncodingError.Context(codingPath: codingPath, + debugDescription: "URLEncodedFormEncoder cannot encode nil values.") + throw EncodingError.invalidValue("nil", context) + } + + func encode(_ value: Bool) throws { + try encode(value, as: String(boolEncoding.encode(value))) + } + + func encode(_ value: String) throws { + try encode(value, as: value) + } + + func encode(_ value: Double) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: Float) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: Int) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: Int8) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: Int16) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: Int32) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: Int64) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: UInt) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: UInt8) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: UInt16) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: UInt32) throws { + try encode(value, as: String(value)) + } + + func encode(_ value: UInt64) throws { + try encode(value, as: String(value)) + } + + private func encode(_ value: T, as string: String) throws where T: Encodable { + try checkCanEncode(value: value) + defer { canEncodeNewValue = false } + + context.component.set(to: .string(string), at: codingPath) + } + + func encode(_ value: T) throws where T: Encodable { + switch value { + case let date as Date: + guard let string = try dateEncoding.encode(date) else { + try attemptToEncode(value) + return + } + + try encode(value, as: string) + case let data as Data: + guard let string = try dataEncoding.encode(data) else { + try attemptToEncode(value) + return + } + + try encode(value, as: string) + case let decimal as Decimal: + // Decimal's `Encodable` implementation returns an object, not a single value, so override it. + try encode(value, as: String(describing: decimal)) + default: + try attemptToEncode(value) + } + } + + private func attemptToEncode(_ value: T) throws where T: Encodable { + try checkCanEncode(value: value) + defer { canEncodeNewValue = false } + + let encoder = _URLEncodedFormEncoder(context: context, + codingPath: codingPath, + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + try value.encode(to: encoder) + } +} + +extension _URLEncodedFormEncoder { + final class UnkeyedContainer { + var codingPath: [CodingKey] + + var count = 0 + var nestedCodingPath: [CodingKey] { + codingPath + [AnyCodingKey(intValue: count)!] + } + + private let context: URLEncodedFormContext + private let boolEncoding: URLEncodedFormEncoder.BoolEncoding + private let dataEncoding: URLEncodedFormEncoder.DataEncoding + private let dateEncoding: URLEncodedFormEncoder.DateEncoding + + init(context: URLEncodedFormContext, + codingPath: [CodingKey], + boolEncoding: URLEncodedFormEncoder.BoolEncoding, + dataEncoding: URLEncodedFormEncoder.DataEncoding, + dateEncoding: URLEncodedFormEncoder.DateEncoding) { + self.context = context + self.codingPath = codingPath + self.boolEncoding = boolEncoding + self.dataEncoding = dataEncoding + self.dateEncoding = dateEncoding + } + } +} + +extension _URLEncodedFormEncoder.UnkeyedContainer: UnkeyedEncodingContainer { + func encodeNil() throws { + let context = EncodingError.Context(codingPath: codingPath, + debugDescription: "URLEncodedFormEncoder cannot encode nil values.") + throw EncodingError.invalidValue("nil", context) + } + + func encode(_ value: T) throws where T: Encodable { + var container = nestedSingleValueContainer() + try container.encode(value) + } + + func nestedSingleValueContainer() -> SingleValueEncodingContainer { + defer { count += 1 } + + return _URLEncodedFormEncoder.SingleValueContainer(context: context, + codingPath: nestedCodingPath, + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + } + + func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer where NestedKey: CodingKey { + defer { count += 1 } + let container = _URLEncodedFormEncoder.KeyedContainer(context: context, + codingPath: nestedCodingPath, + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + + return KeyedEncodingContainer(container) + } + + func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + defer { count += 1 } + + return _URLEncodedFormEncoder.UnkeyedContainer(context: context, + codingPath: nestedCodingPath, + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + } + + func superEncoder() -> Encoder { + defer { count += 1 } + + return _URLEncodedFormEncoder(context: context, + codingPath: codingPath, + boolEncoding: boolEncoding, + dataEncoding: dataEncoding, + dateEncoding: dateEncoding) + } +} + +final class URLEncodedFormSerializer { + private let alphabetizeKeyValuePairs: Bool + private let arrayEncoding: URLEncodedFormEncoder.ArrayEncoding + private let keyEncoding: URLEncodedFormEncoder.KeyEncoding + private let spaceEncoding: URLEncodedFormEncoder.SpaceEncoding + private let allowedCharacters: CharacterSet + + init(alphabetizeKeyValuePairs: Bool, + arrayEncoding: URLEncodedFormEncoder.ArrayEncoding, + keyEncoding: URLEncodedFormEncoder.KeyEncoding, + spaceEncoding: URLEncodedFormEncoder.SpaceEncoding, + allowedCharacters: CharacterSet) { + self.alphabetizeKeyValuePairs = alphabetizeKeyValuePairs + self.arrayEncoding = arrayEncoding + self.keyEncoding = keyEncoding + self.spaceEncoding = spaceEncoding + self.allowedCharacters = allowedCharacters + } + + func serialize(_ object: URLEncodedFormComponent.Object) -> String { + var output: [String] = [] + for (key, component) in object { + let value = serialize(component, forKey: key) + output.append(value) + } + output = alphabetizeKeyValuePairs ? output.sorted() : output + + return output.joinedWithAmpersands() + } + + func serialize(_ component: URLEncodedFormComponent, forKey key: String) -> String { + switch component { + case let .string(string): return "\(escape(keyEncoding.encode(key)))=\(escape(string))" + case let .array(array): return serialize(array, forKey: key) + case let .object(object): return serialize(object, forKey: key) + } + } + + func serialize(_ object: URLEncodedFormComponent.Object, forKey key: String) -> String { + var segments: [String] = object.map { subKey, value in + let keyPath = "[\(subKey)]" + return serialize(value, forKey: key + keyPath) + } + segments = alphabetizeKeyValuePairs ? segments.sorted() : segments + + return segments.joinedWithAmpersands() + } + + func serialize(_ array: [URLEncodedFormComponent], forKey key: String) -> String { + var segments: [String] = array.enumerated().map { index, component in + let keyPath = arrayEncoding.encode(key, atIndex: index) + return serialize(component, forKey: keyPath) + } + segments = alphabetizeKeyValuePairs ? segments.sorted() : segments + + return segments.joinedWithAmpersands() + } + + func escape(_ query: String) -> String { + var allowedCharactersWithSpace = allowedCharacters + allowedCharactersWithSpace.insert(charactersIn: " ") + let escapedQuery = query.addingPercentEncoding(withAllowedCharacters: allowedCharactersWithSpace) ?? query + let spaceEncodedQuery = spaceEncoding.encode(escapedQuery) + + return spaceEncodedQuery + } +} + +extension Array where Element == String { + func joinedWithAmpersands() -> String { + joined(separator: "&") + } +} + +extension CharacterSet { + /// Creates a CharacterSet from RFC 3986 allowed characters. + /// + /// 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. + public static let afURLQueryAllowed: CharacterSet = { + let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4 + let subDelimitersToEncode = "!$&'()*+,;=" + let encodableDelimiters = CharacterSet(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)") + + return CharacterSet.urlQueryAllowed.subtracting(encodableDelimiters) + }() +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/URLRequest+Alamofire.swift b/Instagram-Clone/Pods/Alamofire/Source/URLRequest+Alamofire.swift new file mode 100644 index 0000000..be27c8e --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/URLRequest+Alamofire.swift @@ -0,0 +1,39 @@ +// +// URLRequest+Alamofire.swift +// +// Copyright (c) 2019 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 URLRequest { + /// Returns the `httpMethod` as Alamofire's `HTTPMethod` type. + public var method: HTTPMethod? { + get { httpMethod.flatMap(HTTPMethod.init) } + set { httpMethod = newValue?.rawValue } + } + + public func validate() throws { + if method == .get, let bodyData = httpBody { + throw AFError.urlRequestValidationFailed(reason: .bodyDataInGETRequest(bodyData)) + } + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/URLSessionConfiguration+Alamofire.swift b/Instagram-Clone/Pods/Alamofire/Source/URLSessionConfiguration+Alamofire.swift new file mode 100644 index 0000000..292a8fe --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/URLSessionConfiguration+Alamofire.swift @@ -0,0 +1,46 @@ +// +// URLSessionConfiguration+Alamofire.swift +// +// Copyright (c) 2014-2018 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 URLSessionConfiguration: AlamofireExtended {} +extension AlamofireExtension where ExtendedType: URLSessionConfiguration { + /// Alamofire's default configuration. Same as `URLSessionConfiguration.default` but adds Alamofire default + /// `Accept-Language`, `Accept-Encoding`, and `User-Agent` headers. + public static var `default`: URLSessionConfiguration { + let configuration = URLSessionConfiguration.default + configuration.headers = .default + + return configuration + } + + /// `.ephemeral` configuration with Alamofire's default `Accept-Language`, `Accept-Encoding`, and `User-Agent` + /// headers. + public static var ephemeral: URLSessionConfiguration { + let configuration = URLSessionConfiguration.ephemeral + configuration.headers = .default + + return configuration + } +} diff --git a/Instagram-Clone/Pods/Alamofire/Source/Validation.swift b/Instagram-Clone/Pods/Alamofire/Source/Validation.swift new file mode 100644 index 0000000..1dc3025 --- /dev/null +++ b/Instagram-Clone/Pods/Alamofire/Source/Validation.swift @@ -0,0 +1,302 @@ +// +// Validation.swift +// +// Copyright (c) 2014-2018 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 a validation succeeded or failed. + public typealias ValidationResult = Result + + fileprivate struct MIMEType { + let type: String + let subtype: String + + var isWildcard: Bool { type == "*" && subtype == "*" } + + init?(_ string: String) { + let components: [String] = { + let stripped = string.trimmingCharacters(in: .whitespacesAndNewlines) + let split = stripped[..<(stripped.range(of: ";")?.lowerBound ?? stripped.endIndex)] + + 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: Range { 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.isEmpty else { return .success(()) } + + return validate(contentType: acceptableContentTypes, response: response) + } + + fileprivate func validate(contentType acceptableContentTypes: S, + response: HTTPURLResponse) + -> ValidationResult + where S.Iterator.Element == String { + 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: acceptableContentTypes.sorted()) + 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: acceptableContentTypes.sorted(), + 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 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 acceptableStatusCodes: `Sequence` of acceptable response status codes. + /// + /// - Returns: The instance. + @discardableResult + public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int { + validate { [unowned self] _, response, _ in + 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: @escaping @autoclosure () -> S) -> Self where S.Iterator.Element == String { + validate { [unowned self] _, response, data in + 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: () -> [String] = { [unowned self] in + self.acceptableContentTypes + } + return validate(statusCode: acceptableStatusCodes).validate(contentType: contentTypes()) + } +} + +extension DataStreamRequest { + /// A closure used to validate a request that takes a `URLRequest` and `HTTPURLResponse` and returns whether the + /// request was valid. + public typealias Validation = (_ request: URLRequest?, _ response: HTTPURLResponse) -> ValidationResult + + /// 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 acceptableStatusCodes: `Sequence` of acceptable response status codes. + /// + /// - Returns: The instance. + @discardableResult + public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int { + validate { [unowned self] _, response in + 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: @escaping @autoclosure () -> S) -> Self where S.Iterator.Element == String { + validate { [unowned self] _, response in + self.validate(contentType: acceptableContentTypes(), response: response) + } + } + + /// 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 instance. + @discardableResult + public func validate() -> Self { + let contentTypes: () -> [String] = { [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, + _ fileURL: URL?) + -> ValidationResult + + /// 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 acceptableStatusCodes: `Sequence` of acceptable response status codes. + /// + /// - Returns: The instance. + @discardableResult + public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int { + validate { [unowned self] _, response, _ in + 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: @escaping @autoclosure () -> S) -> Self where S.Iterator.Element == String { + validate { [unowned self] _, response, fileURL in + 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/Instagram-Clone/Pods/Manifest.lock b/Instagram-Clone/Pods/Manifest.lock index 18a8a45..06a495b 100644 --- a/Instagram-Clone/Pods/Manifest.lock +++ b/Instagram-Clone/Pods/Manifest.lock @@ -1,4 +1,5 @@ PODS: + - Alamofire (5.5.0) - RxCocoa (6.2.0): - RxRelay (= 6.2.0) - RxSwift (= 6.2.0) @@ -8,23 +9,26 @@ PODS: - SwiftLint (0.46.3) DEPENDENCIES: + - Alamofire - RxCocoa (= 6.2.0) - RxSwift (= 6.2.0) - SwiftLint SPEC REPOS: trunk: + - Alamofire - RxCocoa - RxRelay - RxSwift - SwiftLint SPEC CHECKSUMS: + Alamofire: 1c4fb5369c3fe93d2857c780d8bbe09f06f97e7c RxCocoa: 4baf94bb35f2c0ab31bc0cb9f1900155f646ba42 RxRelay: e72dbfd157807478401ef1982e1c61c945c94b2f RxSwift: d356ab7bee873611322f134c5f9ef379fa183d8f SwiftLint: ae76d82f056734f853c8cd0371503252c606c482 -PODFILE CHECKSUM: a922d42acc1b5e95ff8835ad84c846cf2ad563ec +PODFILE CHECKSUM: 55ed290f4298d5b68bfee2b32951a89f82fa6199 COCOAPODS: 1.11.2 diff --git a/Instagram-Clone/Pods/Pods.xcodeproj/project.pbxproj b/Instagram-Clone/Pods/Pods.xcodeproj/project.pbxproj index a7d6a07..29c5b13 100644 --- a/Instagram-Clone/Pods/Pods.xcodeproj/project.pbxproj +++ b/Instagram-Clone/Pods/Pods.xcodeproj/project.pbxproj @@ -19,661 +19,754 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ - 000702A76DD1A018D9B45DEB79FB505D /* UITextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA422B8B653925DECD10A82F5864031D /* UITextView+Rx.swift */; }; - 022DFEBF3DD3B5B1627278F189254A25 /* RxCocoa.swift in Sources */ = {isa = PBXBuildFile; fileRef = BABD7A761EC023576B1B30D011691A99 /* RxCocoa.swift */; }; - 0295CFA000CC0A05833225BE4966E6F5 /* OperationQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F17362E34ACF3E2937AEF3326734AF9B /* OperationQueueScheduler.swift */; }; - 02BC9CD938596861D06F0BF200DBD5D7 /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B91A7A9E5D728BE812EADFF1C66A76E /* PriorityQueue.swift */; }; - 03D894819ECA3CA8F42C578E42D08960 /* DelegateProxyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F09AB9864E4B8FC8057599191A758CE3 /* DelegateProxyType.swift */; }; - 0422FC5745E406CB752E9497A2F56EA9 /* _RXKVOObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 5EC3A3C876BB6F997AA895DFC1E92134 /* _RXKVOObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 04B2DDDF8C3C5DAE8952E85BD4ECF6CE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; - 04B641288248D3ACC28E7F707058073B /* ObservableConvertibleType+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6DDD5AE4C8E5CF9BFACA325BD81013C /* ObservableConvertibleType+Signal.swift */; }; - 05D0DB0B68BD602E6AF8C2A9B938A2B5 /* BehaviorRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0580CAACDB221AEAEF5EE46900A661E /* BehaviorRelay.swift */; }; - 05F5C384CDC4BDD7B01E63C3F82D9569 /* InvocableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DF318A6380B535D896F263A1D31A886 /* InvocableType.swift */; }; - 062D7A155A2447CC2BE51F038B44312D /* Infallible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CA2662060A6EFE096AA3BB117ABF465 /* Infallible.swift */; }; - 08155F3F6D55A38A07F00F85763290E7 /* UITabBarController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A8BA0F62E7457838B8C4E134C2A48FF /* UITabBarController+Rx.swift */; }; - 08B6CF630CFB353341DC145F9260B8A6 /* Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD16B00CC1673ECEB6115FAC902E0B56 /* Zip+arity.swift */; }; - 08D08714BCF5A3CA12200BF3A22B1C86 /* Scan.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F036DCFF46DF69F13DA9E48C0B053C /* Scan.swift */; }; - 09997FDBE8364411FFB6F495729608D2 /* Driver+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B51F3BF99D9237CADBEED71883FFEA2 /* Driver+Subscription.swift */; }; - 09E4A424C9A4B6AF425B42861E50E5F0 /* UIBarButtonItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 108B75EB704DE92E5D545B3BC0B813CD /* UIBarButtonItem+Rx.swift */; }; - 0B2165491D9E7087D8C78C7A8128A9F0 /* UISegmentedControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 777FFBD65C0FF1B4A48D8C459DC31721 /* UISegmentedControl+Rx.swift */; }; - 0B91A134E90374448E0CFDB3235525B5 /* Infallible+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 628BA9925CB8D093E9B8045E627C5FD3 /* Infallible+Zip+arity.swift */; }; - 0CA6ED2C33BC2AE8CF0DBC5EBF997E26 /* WithLatestFrom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28A63C60790F5C7200738F8A762FE5B9 /* WithLatestFrom.swift */; }; - 0D4D63DB8DC6713171DBD122D23783F5 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26426EBCCB55CA8014D9D34B51CFE06 /* RecursiveLock.swift */; }; - 0D7B6FF8C492D77C003609B68CFABA1E /* UISearchController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C916D4DC300F09C2F9BA2F32539A274C /* UISearchController+Rx.swift */; }; - 0E1F1CA0797B529C2CAC2956CA1F3DDD /* SerialDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A4ABC1DD59390FF09893BFC0EDECA6C /* SerialDisposable.swift */; }; - 0E6FA44DD92DFE1EC8636DFDD664E9F5 /* ScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 508A20901B2C356FEAAF7D14031050F6 /* ScheduledItem.swift */; }; - 0F75B8C82523266A3DF606A5974073AA /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = 99D05E0077CF60BFE82F418F41B62749 /* Platform.Linux.swift */; }; - 0FAC1DC2496E52AE639614E453BA592A /* Disposables.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC6807AD4C1E67D2C647316CD0ACFE54 /* Disposables.swift */; }; - 12A74636E7AE8263F9F9968EA2BBC7C0 /* VirtualTimeScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B3621E91765CDCDD2F0E491A5418EE /* VirtualTimeScheduler.swift */; }; - 14D2C2DC6532CC4AAD73F205B9211DB8 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6FDDF83812BC79A312D7CCA6CD16F3A /* RecursiveLock.swift */; }; - 154A08CBAA75B8111A87BA7F637F41AA /* SerialDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C350F7C7118DA156B0CBF3C4725BB1E2 /* SerialDispatchQueueScheduler.swift */; }; - 155D953401DF644E75F2ACE729D00DF2 /* Infallible+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 562BCC9B350F163DACF15AA79D23DC08 /* Infallible+Bind.swift */; }; - 15D5D77E68C8B6AF20B7056602F7AEBF /* RxPickerViewAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFE20639826F86C0A485DCE1783C3396 /* RxPickerViewAdapter.swift */; }; - 161856AC63FAA2C3D8164A7500E14CB8 /* UITableView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9251013E40AF2901CABD2FC73CBE7614 /* UITableView+Rx.swift */; }; - 16EB1EAEF9D5FF0D6E4B221ECB397D63 /* RxCollectionViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F88262ECD3611A994C7578DF1AC90D3 /* RxCollectionViewDataSourceProxy.swift */; }; - 171A21B0155EA10267C1DE165A6E1500 /* NSButton+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 369E994557E0AC577044CE1CB58008D8 /* NSButton+Rx.swift */; }; - 1791390AD93AB8419131459DF03800DF /* Single.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7561914E2B359EE2F9867B879662FDBE /* Single.swift */; }; - 194D143B3484967A99C5803AF4FEAA34 /* GroupBy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F12C996DEAA556F70B5F761B97AF62CE /* GroupBy.swift */; }; - 19D3E1EBDFC58CA48AA3F508FB147EAF /* Dematerialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62B3C64FFDCF5AF4054FD532B041ED61 /* Dematerialize.swift */; }; - 19FABB4A23630183D55E62C03BEE35D4 /* Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 767D94760D69C37D5D5D80715BD2399E /* Generate.swift */; }; - 1AD93376D403A851F152D1B804F7BFC0 /* Signal+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF22661CDDC03ED4086D034894D7C105 /* Signal+Subscription.swift */; }; - 1AF3BF0EDE10F429386594F787838C1B /* _RX.h in Headers */ = {isa = PBXBuildFile; fileRef = BE780295A25F4BCABC879D1536A3C54E /* _RX.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1B402AACD54B2064A7BC86857F2769DD /* InfiniteSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1640FC349F21362CD2F1E8C375FEB710 /* InfiniteSequence.swift */; }; - 1D1E1B6DB82B5D478BBFEB38088B1651 /* Maybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D63B0B75043E16A5215A4ECA19471EC /* Maybe.swift */; }; - 1E9033562EACB851BBAB74F033194B48 /* RxPickerViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2235370476372BE73664E895A421D4FF /* RxPickerViewDataSourceType.swift */; }; - 1F49C9115FC34EA07139974045770A67 /* Do.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2B24E3FC4E0E31678BE3D07FE5B5546 /* Do.swift */; }; - 20588EFAFB30DD4317FB2EDA75B0DECE /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 089965FFF10BAC759D5721DA13057A92 /* Repeat.swift */; }; - 210E6BE763C894C38888F5B166A2EA64 /* PublishRelay+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD24ADA98445D4184D06F84FC41D11E7 /* PublishRelay+Signal.swift */; }; - 21DC0A2D2A64CB7511A4FA138072161C /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BC86CE63EC0703205D3A01D0D570F08 /* Just.swift */; }; - 2375EDAD8E10B3DF818E18FC14D3E509 /* Infallible+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D8C3064DA8BE2AD59875B2AA63F7D8A /* Infallible+Operators.swift */; }; - 238C4A1EC8BA1D3A575ADA67F68CD09C /* ControlTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = A175A343983FD9CE1E9FA110FB2F40D8 /* ControlTarget.swift */; }; - 23B9CAC8AD17E0E048E75732BA9CB675 /* RxSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C1D6D0DAE2CE5850872E7FC3538FCF /* RxSwift-dummy.m */; }; - 24C44D889CCC3570C277EB1C3CE505F4 /* UIButton+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D6DBC599BD63D72D8E840C6A338EFFE /* UIButton+Rx.swift */; }; - 270C6886BAA3FC9C18D0DF59F6B164FD /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7608E2D33CF20C31B9FA50AF57E5FDF9 /* Throttle.swift */; }; - 2722C9B25CF57D3AE89825729DEA9BED /* DelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EE9FE35EE4E7109EA34CC2443F5C817 /* DelegateProxy.swift */; }; - 27D5E789967F99EE82FADEAD73D83459 /* Observable+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = B06D287CBC4CC7C094B544F533F4CA65 /* Observable+Bind.swift */; }; - 289B486CE0DC17D17817EC988F341CE9 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70664A49465BD35C219845778B09404D /* Observable.swift */; }; - 28D5D9EEAE845C76C8079BD1C77BFE82 /* RxCollectionViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B92717286BC70F18FCB3A9C3C72A5C6 /* RxCollectionViewDelegateProxy.swift */; }; - 28DDBE36EE067086F4925C830D668FBA /* KVORepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1699725A75E793AF47AFA08A03CAAFA5 /* KVORepresentable.swift */; }; - 2A6A7FA29F2A569A74F5DF329060C30A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; - 2AFA355C5FFE96278B4F2ADA01AD68A6 /* GroupedObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F09AB4C59893AD412B9A8974A44EFAF /* GroupedObservable.swift */; }; - 2C64E385669A619F264F7556914DF205 /* UISlider+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0775DFAAB9181064CDE9A004E96E7D3C /* UISlider+Rx.swift */; }; - 2D1B4021AE7EB95A36DAFE3CC858082B /* ObservableConvertibleType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8748A054157E6C52B89C50AB9294372 /* ObservableConvertibleType.swift */; }; - 2F336C33B921805B1B5E49EC63BFCD68 /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E80158E8E533E6E6412E82B0007A6D43 /* SynchronizedOnType.swift */; }; - 307CAB3C89EA02A51CDD5C11A4EDE036 /* TailRecursiveSink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 898AC549FA3207BF3C86263F8BEC9241 /* TailRecursiveSink.swift */; }; - 30E0289934EEBBB76CBEC3063F461F86 /* RecursiveScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = E58AD4BEDFFAF702BDB724E21A684C6F /* RecursiveScheduler.swift */; }; - 31F0D187BC76DAB3C2DEE8B2CABB0535 /* RxTableViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D83A8EA89291EB91728C988DC3AE885E /* RxTableViewDelegateProxy.swift */; }; - 33178EB30F3F079DB41FEDE82E7C331C /* WithUnretained.swift in Sources */ = {isa = PBXBuildFile; fileRef = F498B2C52627D4B3747D8E8D2ED83E9D /* WithUnretained.swift */; }; - 33BFC526BF10EBF07C927DFC75AFF826 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D7FC2FBFC96464543FC2D5284CC469 /* Error.swift */; }; - 358F0A3017B7486ADE25FD5ADFCA7904 /* ConcurrentMainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F9CFCE6985273F3DE45053967790C1D /* ConcurrentMainScheduler.swift */; }; - 377F7F2ACDAEC9FA1E6A515894AC97C6 /* Bag+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6788801F19DA52CA8EE23A3201EFCF2F /* Bag+Rx.swift */; }; - 37D6A7E0FD0E450761120C976F95EA73 /* BinaryDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8892F4474BA4B9852E09846DC7B861F0 /* BinaryDisposable.swift */; }; - 3881A1E025B3561AE179F9FDAE57187E /* Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D7F8F13AF4282C1D19D4B2E42A5FDE3 /* Materialize.swift */; }; - 38D0534EDDC37793282AD797DF3CF4B0 /* Observable+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6878C434F38257C935BFBCB7DEB933CB /* Observable+Bind.swift */; }; - 3AAFB9CC4F818A8B787A6B77464B18C7 /* SchedulerServices+Emulation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B14FB3822E731DB6D717BCE0D19DEE /* SchedulerServices+Emulation.swift */; }; - 3AFEA39C21C700AAB86C4ACD9436D357 /* RxCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 3F03CA510076C25FCD452E992F2EF3CA /* RxCocoa.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 3B82FB00AD02652E1801233E5684DB1D /* NSControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9AAA50BFDD2E0E8D502F4ABE2600B8 /* NSControl+Rx.swift */; }; - 3B8549624DDB175C02265F177609376F /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE52486EB2B3A9A3A429A00A5754CA9 /* Event.swift */; }; - 3D42C9D3EEBE1EAD7E365276753FE99E /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8EB9624A417AD927C74289745F8DCAF /* Queue.swift */; }; - 3D445FD9D8FFBDD79E0D04BDFE96B0BB /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA218DB75EBB15A3A1EF4327B71DC923 /* Signal.swift */; }; - 3DD9694A6D1F5035C6C400C6912B9E36 /* RxCollectionViewReactiveArrayDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 007E7595BA898B76D1D326F44A95B104 /* RxCollectionViewReactiveArrayDataSource.swift */; }; - 40AF681341B77C5E2896E507F65E8B39 /* ObservableConvertibleType+Infallible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60D291EF382DFED378C9057592F06218 /* ObservableConvertibleType+Infallible.swift */; }; - 41752621D36551F16F12C44CEE1F5166 /* RetryWhen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04344BD8BBAE6840F81D834C19D77C19 /* RetryWhen.swift */; }; - 4362AA421B2EE7A28A3731E7ECED59A6 /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = E540F3DE703DD3BB653266C40509D28C /* SkipWhile.swift */; }; - 43C88503368D2779C7C7F8B203AFA34F /* Take.swift in Sources */ = {isa = PBXBuildFile; fileRef = 338E26527677E48EDF3516E1ADA885D0 /* Take.swift */; }; - 4441C02A32D1D469F208A5925BE92467 /* ScheduledDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE7897050459FE64BF884DD0F493CCD2 /* ScheduledDisposable.swift */; }; - 446F77EE27F2DE7513D3D43FDDD4BBFD /* DisposeBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935118C1700F1FBAF0850D84AC0BF44A /* DisposeBase.swift */; }; - 447A2D4A1D0162C87280DF7C59E9FA29 /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C50211D78C2371DED7C720B94CFEF /* Window.swift */; }; - 44AEBB2D29B9FB87530556A0CEC170F7 /* RxNavigationControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AF6C495B29F03325205155A225A54C3 /* RxNavigationControllerDelegateProxy.swift */; }; - 45358BFBB698E1F6B71BFC5CAEC76FC4 /* InfiniteSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5039A8657AC236E4C8277A1A9039360 /* InfiniteSequence.swift */; }; - 4645C8DB11FE2FA7836124E77A768650 /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15299F3579C722B10ACF13813B53ABCA /* Timer.swift */; }; - 466E1FA9DC6F99B0C6B6B5F4251FDF47 /* ShareReplayScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F124CB1F0EEFE46E9400A8A5A771D5 /* ShareReplayScope.swift */; }; - 473F1C89DF4F981A9231DA64B7959E75 /* Reduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72046CC8FB967C35B5E0DC3F870678A7 /* Reduce.swift */; }; - 47B48B7531CE161773DEF0B851D08037 /* ControlProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B6EF5FB2BA8D6F9CA45221D11FCBBA5 /* ControlProperty.swift */; }; - 4838B3C8759DACF738F61BF91100379A /* RxTabBarDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = A49C6178A71EBA0C7BE086BDE5ED1E66 /* RxTabBarDelegateProxy.swift */; }; - 4878A6C8BDEF6FCC155719CA93BA9586 /* _RXDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BAE0BC077E8C62320097689E54D211B /* _RXDelegateProxy.m */; }; - 48B27B6A17D7EABB0246EB78751E67AF /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF1514228AEDC411709E7F1E8DD9A1A6 /* Utils.swift */; }; - 492CE2AA2B9DDE29FA77A9D29BFA88D6 /* BehaviorSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB43DEDAB36933CD1961B889C31CEFDD /* BehaviorSubject.swift */; }; - 4994F1CABB9926703D82BA0D9D66321C /* RxCocoaRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C4B4A36966A9C04C9538B5C5E2150C6 /* RxCocoaRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4B745396FD1223BA8532DFE2216E043C /* NSTextField+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21ACAD4D869127D49821CD63EEE486D1 /* NSTextField+Rx.swift */; }; - 4D19C1FCCFA37B3EEBCD874A8A4A5AD3 /* Concat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 383C2AC03F6C6BD740AEDB5F72435FBB /* Concat.swift */; }; - 4D4C9A22FE30B0D37DB1D283D1B6A804 /* StartWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92E5B6359027EBC6DEC81A16B89FBBAB /* StartWith.swift */; }; - 4EB4328C78B36211BF7D50529327FD7C /* UINavigationController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59CF1146BFFC0D96B3CC4F517DE8E4E1 /* UINavigationController+Rx.swift */; }; - 4EE0F2D2112CE993AEA24549F5DB19BF /* UIControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3A5DBD1144DF1DE9D79D0DE0FD9FF9C /* UIControl+Rx.swift */; }; - 4EFD31D7DB8D26D9D031A2225A0C6AEC /* UIApplication+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F297B2AB79CC5002645FF512CDC17EB /* UIApplication+Rx.swift */; }; - 4F744303AF9B5E7CEF8C3A9327E852B9 /* ControlEvent+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 791B8B0D9B49A4D288CFDE5AFAC9101F /* ControlEvent+Signal.swift */; }; - 4FA389E8CCD45D266A3FBB6F8A445855 /* ObservableType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6943A86D4C4C86816F275975A3F56777 /* ObservableType+Extensions.swift */; }; - 4FC27FF6DF0328A134393A57E735977B /* RxTextStorageDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E0254E101D267C71ECFDB98B9CDD73 /* RxTextStorageDelegateProxy.swift */; }; - 4FC9E9B4D558C89C8EF7144529E26449 /* ReplaySubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE5CAA2DF30E75CB6DBAE64575FAB211 /* ReplaySubject.swift */; }; - 50681D70D26BA315A5DDC1365B4CF0BB /* KVORepresentable+CoreGraphics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 359C8B4E3F1950C1B077B313A05E98AC /* KVORepresentable+CoreGraphics.swift */; }; - 5084C64F70AC0E22C44BD5B465F08BA7 /* Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD8DB1146C2FD3850E2DC90065612219 /* Debug.swift */; }; - 5089A93E147C25A4660F838231150204 /* AnonymousObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3399CFBB1396ACD6286EBA4D81D4D0C /* AnonymousObserver.swift */; }; - 51C984425C777CF8B613C230DCE2DB65 /* UIGestureRecognizer+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFF0ABC6B463C32F017539E758D6582 /* UIGestureRecognizer+Rx.swift */; }; - 527135A13489F35CD40B860DB3C9AF82 /* Catch.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCA80E4EC28B8A2A8DA36ABC61F686AD /* Catch.swift */; }; - 5291A92FB6C7E3FB265DC22EDD908884 /* Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = D174A224B1906B2C2C1AFC4A244D0D7E /* Driver.swift */; }; - 529BDA5E8CE104C4B384017447D0DC60 /* _RXObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = 01AB5F3B630755C56EC18F68BF4C67EC /* _RXObjCRuntime.m */; }; - 52CDD18140E6FE4BE418B6FBDCA1F4B7 /* ObserverBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF284C36287FCF12DED05CABACB2BA82 /* ObserverBase.swift */; }; - 548B9145185925F281D9B1951379E6D1 /* RxTabBarControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF7CFF4144277E2FAAAB06F989F256D1 /* RxTabBarControllerDelegateProxy.swift */; }; - 549DA3825EF92864B1FA9FFCF99F2537 /* ScheduledItemType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE14BF9AF5DB36145DD2FF859822332 /* ScheduledItemType.swift */; }; - 553950D2C5D7058D7F6AC96C3F508060 /* Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BCC3DE64EB6BD619B9D9CF5F8E5F1F9 /* Timeout.swift */; }; - 585F7A5B3484C702B1142C4D99F09E0E /* ObservableType+PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1D7D698F8E89D6A74D2068A57CD9019 /* ObservableType+PrimitiveSequence.swift */; }; - 59691189B7A014BB0230561AC0A489A6 /* RxCocoa-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C61DA0F4B8F6066A14AEF98A1D31D00 /* RxCocoa-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5999CC5A3F84BD421AE116E29F47B83D /* ReplayRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34C096CAE0E50C543DD70356A57665F /* ReplayRelay.swift */; }; - 59BA69203E1EAD6065517250EBC344AF /* RxMutableBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE3973E65F651392AEF7DF2E8E748EA6 /* RxMutableBox.swift */; }; - 5B06F69235E0E8E680E6A4F68951A8AD /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92A7E4BD7E45FB638F049D2CF3272D20 /* Lock.swift */; }; - 5F613B97C5A9FB68E45744D3708AAE25 /* RefCountDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5232F0716373C6707AA30C634546FCAE /* RefCountDisposable.swift */; }; - 5F653960E8C236643ADE4D33DC6B987C /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80F107C23AD0B22789290606EDE7C423 /* SynchronizedUnsubscribeType.swift */; }; - 5FB4CCABB0B94E40E68A7A4142E487C2 /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09783CE839BFEBF2D75D0FDCD24233B5 /* Platform.Linux.swift */; }; - 6221DA074DD5611302639D8136AAB3BD /* Merge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2C66B37865A7C240E9B137458195DBA /* Merge.swift */; }; - 645B4FEB58991182E0EDAC1D3E694247 /* SwitchIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9044811BD3FCD91090DAAB658671FE6A /* SwitchIfEmpty.swift */; }; - 6468B3694ABBC835D9FE3CA6F2BA44B9 /* Zip+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2385E1134EA158765A41A546E3AE33BC /* Zip+Collection.swift */; }; - 66451B72DFC713F4784A0C107AE67C34 /* ConnectableObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FB3DECF9FA15E273D3F48AA2E9AEAB7 /* ConnectableObservableType.swift */; }; - 668A595C1895EA60A365B0CFF9636846 /* Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 544B2D6150A77A085C21CB5926471FE1 /* Delay.swift */; }; - 6721B4F8556A903296754D565939E2A6 /* Amb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69FE9077C79452DD8408F90206503B5D /* Amb.swift */; }; - 6824A31E76DD054D44A3B14B69335858 /* AsyncSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E3A902E1F2FE5A95218F7934C84C30 /* AsyncSubject.swift */; }; - 68623BC382EACE93D53213D1D5AAAD3C /* NSTextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACB0E157337542EC91EA1D85D49A693E /* NSTextView+Rx.swift */; }; - 69537EEBAEE542798C9630CB8F96DF8D /* NotificationCenter+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00644668DE9E29E96EA7D4E75CC41005 /* NotificationCenter+Rx.swift */; }; - 6ABE5C6E5B9C3F361B716B482E174666 /* SingleAssignmentDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4670F49FCE04BE2C9B9127D7C02F25CB /* SingleAssignmentDisposable.swift */; }; - 6D8CDC66C950346874056F3F45FAB0FC /* NSView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44CA33D5BC8739EC2CFFC5E68FD0A0E /* NSView+Rx.swift */; }; - 6FD8007E70E3D3FE65EEB9A576ACE6E0 /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DE31BF75E95FE12CF6EB3E9941E03E7 /* DispatchQueue+Extensions.swift */; }; - 70527867C4C4C965053E4283F3778986 /* RxCocoa-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 44C06230C881B6028853B66557DBFEE6 /* RxCocoa-dummy.m */; }; - 70A41125865DDF878FC4CBD646349805 /* UIScrollView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17385DE72069A424DE83D6B4072A92A5 /* UIScrollView+Rx.swift */; }; - 70C2D5C7F8CE4C996556072B546BAB01 /* Completable+AndThen.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBED721EBC4C0D72C86FCFB0430E6C7D /* Completable+AndThen.swift */; }; - 71D5BDF4D210C1DC54AB197B1D2E9D13 /* ControlEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 800125918B1A34EEA9B5EBF32842ADC6 /* ControlEvent.swift */; }; - 7252D3B557D3BF17CBAAC5B6878A18DF /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C78B0D2870B348AB740CEAA27C2E74 /* SynchronizedDisposeType.swift */; }; - 72C98497431AE93DFDBC57EEE2D20C35 /* AsMaybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9584F2AD1F12E0E0F15B714F0CC6E68F /* AsMaybe.swift */; }; - 7394A3EA44F09919B4D5BE4C9F642AA0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; - 770B72F721A4554BB4C3A4F2556B8045 /* AsSingle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF8210EDCD60CEBB76BA4E5DD73C877 /* AsSingle.swift */; }; - 779270736284A8CA1DB0BE207D806535 /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 253971F450F05D5006DDD0D919450D87 /* SubscriptionDisposable.swift */; }; - 77DE7B1A171A8A834D1C829CAB53DC8E /* First.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0B47045699682A1F80DB7EC82EF7EC /* First.swift */; }; - 7B9E0259D63E7DC7C4A15A116CFD20E3 /* Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74B7F67BA3B530028F633568D0A7D4CA /* Empty.swift */; }; - 7BEF420E8F9099C5079845A9BE4DCA63 /* RxWKNavigationDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E09D984913B78C1ACC200E9E15BE4ED1 /* RxWKNavigationDelegateProxy.swift */; }; - 7C0DC741562A17F09F60EB9329DDA7CD /* ControlEvent+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE159A12F2C43C59116A33FFB85E05D6 /* ControlEvent+Driver.swift */; }; - 7C503EFAA5E9AD2FA2A436E8C1A75A44 /* ObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B30D4AF1264D8B0677474E3A66F22172 /* ObservableType.swift */; }; - 7E3402342205B2DC03468A7FD95F61A9 /* NSTextStorage+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49739CC03AC63404753D77D10DED8B2 /* NSTextStorage+Rx.swift */; }; - 7E8F6522AB2F462F4C8E7DDBCE073FFC /* PrimitiveSequence+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = B810010130BCEDC6EFDBEFAA3F5E138F /* PrimitiveSequence+Zip+arity.swift */; }; - 7EEED39CE5F3611AB4D7205FD038021E /* NSObject+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5104C7B97A69637D48E0917C458C948 /* NSObject+Rx.swift */; }; - 7F27F23934F685925D4E1C3629F8B5F7 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47C9C5568753DC4ABA0764707F468FD3 /* Buffer.swift */; }; - 7F60B371FE78073E7DFDD621FFC482CE /* URLSession+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = E48B6ACD2E4F63EB00A01373EFC62314 /* URLSession+Rx.swift */; }; - 80487E786F9E8595C97CC019819F54DB /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7CF4533A429B848A2569FE826DFC277 /* Queue.swift */; }; - 81A394201D240F032A6108ED479B427A /* UITextField+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B35CAAC7C2C89492E1A53DE25F9C8C35 /* UITextField+Rx.swift */; }; - 841FBD1EB10F9112D309BB28BD10CF1D /* SharedSequence+Operators+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8403ABA7A5EF2EC532F05258F9862B4B /* SharedSequence+Operators+arity.swift */; }; - 85C215D20BE5E66A0D4F7A8E6E1438BA /* SwiftSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40661C9CD5EA78C14FF62DF719B11B18 /* SwiftSupport.swift */; }; - 894BF76C4272C38C9E17385110BF4A41 /* _RXKVOObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A35B44531A4D80CEAB2B91D2C3B1F93 /* _RXKVOObserver.m */; }; - 8AEF0775CDF920AC2DBE0C725B59EC96 /* UIStepper+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9880E80FCAA42588A804BA350064BE /* UIStepper+Rx.swift */; }; - 8B7686A732E13434E997809196B15955 /* UIRefreshControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE1B73E6DC096DBF6B3439E935446EB7 /* UIRefreshControl+Rx.swift */; }; - 8CA954A1E8DDAC844F88DA711D66FDF7 /* Skip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90009E81E181BC430376EC477FF1561B /* Skip.swift */; }; - 8D699C4D8028F3076F60D47B9C88E45D /* Pods-Instagram-Clone-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = C4E2F629E6629BB14C3AA2C13A4D05EE /* Pods-Instagram-Clone-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8E1CC3D54AD8D9D06780C564C24D18AA /* ObserverType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3A723B60F3BBCF212075132049E83DF /* ObserverType.swift */; }; - 8EA5CC7EF28B004A8A813925E4F17F93 /* WKWebView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9255CBB2D0BDBAB46779F2BE12C9834B /* WKWebView+Rx.swift */; }; - 8FE0BD68EA39B931E49D9C038BE80B65 /* UIDatePicker+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE05D49A0D640FFF40FF956D3870AE70 /* UIDatePicker+Rx.swift */; }; - 938B46EF411204D0BEE0A56A7D584D51 /* RxCollectionViewDataSourcePrefetchingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D7E732DE2B0F4DDEEB2A48C3793EA57 /* RxCollectionViewDataSourcePrefetchingProxy.swift */; }; - 945DBBCB62542CD24B29F83FAFEF13B1 /* NSObject+Rx+KVORepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EACCE5DEA2BBD802FE23A452B0498E8F /* NSObject+Rx+KVORepresentable.swift */; }; - 95181366D610146E29AD34636DB9EFB7 /* Platform.Darwin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193BF64313DB29C3FCF62CB0CF3133BD /* Platform.Darwin.swift */; }; - 9521D073AB7B8F3F4D8198CA514AD699 /* DisposeBag.swift in Sources */ = {isa = PBXBuildFile; fileRef = C66DA023B9D646DC6A225AB65C154D7B /* DisposeBag.swift */; }; - 9850A80051F5259DF4BD9060DEFE783F /* BehaviorRelay+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 610CD268ADB35154B7AA77C94FDFE206 /* BehaviorRelay+Driver.swift */; }; - 985C1E80CAD53D9EBF3C366FC3B90B1C /* ElementAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 404475EF1E226D1D3703A1AA7D0F355F /* ElementAt.swift */; }; - 98BBA8C13C9C407DDB402708D6C1DDFC /* Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55502E9CDD82DB3C088023E52EF29CAF /* Create.swift */; }; - 99B75C980B7F5E81A5CFCCACB57ECEEC /* CompositeDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C255FF4F123BF4ECE7E8A1C5821F51FF /* CompositeDisposable.swift */; }; - 99BAEAC4A09CBE44FA6D6772C18278B6 /* PublishSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 619F731B252F401E63D0C2EE802F83C5 /* PublishSubject.swift */; }; - 9A0606B12634DDED8A0EA1EE72FD56B6 /* CurrentThreadScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A9924027370221407B27E38E6125CB /* CurrentThreadScheduler.swift */; }; - 9B6D684A7CCF9470B92E10267E3987CA /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC5124547E5FFED02E336C7C60B257F /* DispatchQueue+Extensions.swift */; }; - 9DB4A288E7875E7346EAB537875222D8 /* SharedSequence+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6F2C49E08301D6E1CC8CAC4EB7B5905 /* SharedSequence+Operators.swift */; }; - 9F91138ACA7962F49DB2CDA2EB898ED8 /* NopDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C591B3A68D801DC242DC1D3987FEE92F /* NopDisposable.swift */; }; - A001F99FC48A2CB820E977146AE31F54 /* TakeLast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 523F251A7D75246E6AEF64CEE3209F7A /* TakeLast.swift */; }; - A1194BE78FCE2929CDA65C95CA310EAF /* RxPickerViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B129863F6D3DDCF8834A7AA74F387E92 /* RxPickerViewDataSourceProxy.swift */; }; - A1985C2CC5030AB984FFA33B94E1E39D /* ControlProperty+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F6E8678CF19A4F655E0533A1909983 /* ControlProperty+Driver.swift */; }; - A2F7FF2AEFF21D78671543FA8CB6A8B3 /* NSObject+Rx+RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A24B6007154434755D6FE7829B75E1 /* NSObject+Rx+RawRepresentable.swift */; }; - A3423ADEDFB20D72E2C608221A26D3C6 /* UICollectionView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 944D4A34E4D244179DE134F59EFA997C /* UICollectionView+Rx.swift */; }; - A37D3661369446F3AA978C8FD342A83A /* UIActivityIndicatorView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06BE21461C247B540A28540AD7B0C5F0 /* UIActivityIndicatorView+Rx.swift */; }; - A416110399B7A9BDF7D85DF2F597F00C /* AnyObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87911FA9E065451BD946DC5DF3C59D3C /* AnyObserver.swift */; }; - A435E4B3FF0B326E880502C6FD3FC987 /* KVORepresentable+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D86B6152B2D9A5AD3AEBAD65A7FD53 /* KVORepresentable+Swift.swift */; }; - A52A96F5C18BB006098DEC94C4E8CC3D /* Infallible+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED8F0268E6C47E5861B76EA99770D8B7 /* Infallible+Create.swift */; }; - A56CD1D3422F2829C360685A02D7A9AB /* PublishRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7A312365200557E6349C200AA39470A /* PublishRelay.swift */; }; - A877585244D5066F98821D45EF0715EE /* AddRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = D98877E126D60C268E5194134E3EC82A /* AddRef.swift */; }; - A8FDCEA60F22D974B678CC68FC0FC933 /* ConcurrentDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C4AF57E2F918529D2AF398E1E5CDFB /* ConcurrentDispatchQueueScheduler.swift */; }; - A9A21661CE07EA9A179E3D077CB5013A /* Debounce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AC87BA30AF3E7421DB0DD8D9A73F869 /* Debounce.swift */; }; - AA7BBD3390AF2ECAFA1AD576BB69CE15 /* RxScrollViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97582CE90B36CC35E3344E0B3BB9E8C2 /* RxScrollViewDelegateProxy.swift */; }; - AB4875CA5028C3C32274EC2CCDFE9066 /* NSSlider+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4A85B1C742FF6712B8AB28B47273634 /* NSSlider+Rx.swift */; }; - AC813524AC3288D8D7211D0460FEB9C0 /* Multicast.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF6D9B3D35590C7721824E06FC38BC7A /* Multicast.swift */; }; - ACA0685005609FA22A3C7EB8C70EB94B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; }; - ACB7287C66F652838DE45D5FBFD441A1 /* DispatchQueueConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F136EE513E530DD4746D00FF450D357C /* DispatchQueueConfiguration.swift */; }; - ACC6FE2A0154AEFA723F19B387B98306 /* Never.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40671A9B964030A4CE7429E95CDB983 /* Never.swift */; }; - AE699CB7ACA4FD73BB4D02A856683B76 /* RxRelay-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 64388E578D1FB97E4DB5775A469337F1 /* RxRelay-dummy.m */; }; - B283E0B7BB5A5910188B1B4C7B15FF53 /* ObservableConvertibleType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 499F02441FA51A23F940FA3843DF9A39 /* ObservableConvertibleType+SharedSequence.swift */; }; - B319ABE0B5A79B265AB9EC265BA32FDC /* ImmediateSchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D0818786883B7E84DC3216C80C0F342 /* ImmediateSchedulerType.swift */; }; - B39AE6FCDDC339B7EA69C041DAE7FED2 /* CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3532C567B8EB7BAB306DDA6CA277B84D /* CombineLatest+arity.swift */; }; - B43BF0B2405F3E9368D5F86AD2834688 /* Deferred.swift in Sources */ = {isa = PBXBuildFile; fileRef = 546E57E00BC246C6761986A013FB0DCA /* Deferred.swift */; }; - B52B575A4656A46645F3B5A999917A14 /* AsyncLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E585039525D24078FD09A43C1FB4E2 /* AsyncLock.swift */; }; - B53149262AC23819BDE17E15E4CEAC8B /* Completable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D9539B4F49FEE65309ABE756D3F4786 /* Completable.swift */; }; - B5CC471C9EA6B4D9757FE55A807726BE /* ObserveOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F533CB02A453B09B128C0121F309F99 /* ObserveOn.swift */; }; - B75EC99EE9B6D74230B05B192A373DBF /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61D33EF3A2C81402ABFD71409496E49F /* Decode.swift */; }; - B8E27E8D24CBE6DB22F38E06FFBDB710 /* _RX.m in Sources */ = {isa = PBXBuildFile; fileRef = 3F03494C7F9242E59237EC6E7B3A8D6F /* _RX.m */; }; - BB75BCF76F22254E3302085A5A6A4B48 /* SchedulerType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C37D5F564EE6CB890C291313BEE75AA2 /* SchedulerType+SharedSequence.swift */; }; - BB95DBF30DBBC9F53363027CE1BB422B /* Date+Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8AB807816C8B19247B4695711078D12 /* Date+Dispatch.swift */; }; - BEFE617EABAE8B434A580CCD4179C04E /* TextInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC9D60AB695554951311124842EEABC /* TextInput.swift */; }; - C02096C50B5EC4D188E0DA02905257AE /* SchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD02EB1D4A7B9800C069F8CD6EC1CB34 /* SchedulerType.swift */; }; - C0CBBD9D2153C76CC4A124321F66DF55 /* HistoricalScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C55F92F39ECE075EE04F1D61EFC0326 /* HistoricalScheduler.swift */; }; - C29F61C558148A9A7401DB6AF57FF214 /* SubscribeOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 149172E51A3A87DAF5B5A38EF9199C6D /* SubscribeOn.swift */; }; - C30F1E1AB8A93311FE04381989A8CEFE /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAF3426B2E09A3FD26E570F5435C1C4 /* Sequence.swift */; }; - C328725EBFF411F9858C9326D3ABD0F3 /* CombineLatest+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 767BA97D4F49BFF48996CDFDCEDCAAF5 /* CombineLatest+Collection.swift */; }; - C3C83569578601F779F1BE1DB50386DD /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = B09EC6A25D0F81AE425C42CE3E04DF34 /* Optional.swift */; }; - C435863C953D4CC4E88EA84B950E710F /* Infallible+CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A570E94AC7743F742308E9408C3DEE9 /* Infallible+CombineLatest+arity.swift */; }; - C4D350D569A2B6567E087ED515A93EE2 /* RxTableViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2825DBF5B8A8DF6608934526497046A /* RxTableViewDataSourceType.swift */; }; - C506645305BAAB18BD37A354C03CCECD /* Sample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E69A66DD64CE026C3088FCE23AC5A8D /* Sample.swift */; }; - C50EFF96E2BB35B40F02BFFC7624791F /* VirtualTimeConverterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D6F74828D23AA06327E94D4B11F0483 /* VirtualTimeConverterType.swift */; }; - C56A14C84CF05A1A96D8B92E16E0CBFB /* SectionedViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22BD2B18828CB266956CE4D931265F42 /* SectionedViewDataSourceType.swift */; }; - C58770A749AB10BFF4C26B35117881FD /* AnonymousDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75BD1907BE8577B050A2AD8FA2FA7B75 /* AnonymousDisposable.swift */; }; - C5A26E0FE94871E9445753078C059AFF /* HistoricalSchedulerTimeConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7F5C6548DC2DC42FDA589FD0A2E46F /* HistoricalSchedulerTimeConverter.swift */; }; - C66C4E3E67C26B960FABBC8F1B0C056A /* RxTextViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1ED4EBF7B0699C1CE93E1628B4EA1B8 /* RxTextViewDelegateProxy.swift */; }; - C6A45564D562250B2B44FEEA9817DD8E /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 299E7425E04B095442F4A077219619DB /* Bag.swift */; }; - CB14BA773C9A13976D90006D9A843379 /* Pods-Instagram-Clone-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4894F90605FBEA7B041ED3C5E033C0EC /* Pods-Instagram-Clone-dummy.m */; }; - CB609631B3F62445002C65C34BFE747A /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = FABADFC21256981C272E6D78A090EC30 /* Map.swift */; }; - CB817941DDB243A69908CEF658DB7FE2 /* SingleAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E04188FA34CE390796D91FF5E2B8886 /* SingleAsync.swift */; }; - CB88E214712F902A3BDBC2B1582D80B9 /* MainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AC378ACD31FBB65065DB9EEDE4599CA /* MainScheduler.swift */; }; - CDED4A952693B2BD16556F11FE171FF3 /* TakeWithPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1ED315F78613719616BD46F58A69425 /* TakeWithPredicate.swift */; }; - CF9DAAEC618DE435A7DF19579DE30AA2 /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D864E28EC1869A5B35ECEDD2E5D8C68 /* PriorityQueue.swift */; }; - CFDB789808F3EFC72BD379080F6D4F1B /* RxRelay-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 742D5848876230A2E30823D4FDE0FDB0 /* RxRelay-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D05116642C20C568B926B4025B6EF995 /* UISwitch+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED909CFE87DA665DEA46BF2B7B8CEA03 /* UISwitch+Rx.swift */; }; - D1DE14077A54174F00E887101A48AE8A /* RxTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 193EB48EF2C7E8AFF355077AEE6C05D3 /* RxTarget.swift */; }; - D1E7DB962D3779DFE587BCED867E7BF9 /* Platform.Darwin.swift in Sources */ = {isa = PBXBuildFile; fileRef = B40E371D7A6BBFB7E8FE61981378D673 /* Platform.Darwin.swift */; }; - D3179A1825ED194F1972EA6A3F0DD85B /* Reactive.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0A7DD927A1CA40ACB4A31136448C7B6 /* Reactive.swift */; }; - D583F8FC3BFE7CE7368F5FE75679F388 /* RxTableViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9080BDB30A4F4776904377290A3551C /* RxTableViewDataSourceProxy.swift */; }; - D709A58FF6A694878122F7D24B4A9913 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D88D012987C2AB388AE2C7B2EC57E9DC /* Bag.swift */; }; - D8077E1CA5DB15B51BEBCC634FF30FCB /* Enumerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 69C99F11DF4D911FF5F58FF99637AEA8 /* Enumerated.swift */; }; - D8A4FE44301CF797B3E9655FA9F80FA6 /* _RXObjCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = EC1D1864465B4C3358F1536A4A8A44EA /* _RXObjCRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D9831CF6644519EA56FC7D1AD87D0E86 /* SubjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5034BAB8BD865EB2CEB711500C270EB8 /* SubjectType.swift */; }; - DD724165EF3D8F209BD6EA6EEAA7EA0A /* RxSearchBarDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DC79611286237FB7BE7F29EDEB2421B /* RxSearchBarDelegateProxy.swift */; }; - DDEF2B45CC47E733C9FCCD38F0BF6857 /* UIPickerView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23CF8C2915AF525BE23908E7FE1610A5 /* UIPickerView+Rx.swift */; }; - DE8F6179F22AA4E593D23C6CD4529FF2 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A6F4201F3E82652819407100545509 /* LockOwnerType.swift */; }; - DFD30F96D602E6476B57BB16FF1785D2 /* SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B83A6E4784CADA73C8A18D843D3AA5E /* SharedSequence.swift */; }; - E1056A74E23F1D4CC7D6E54CF67A8E0F /* DefaultIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761783ACC956844B0C427D1A56C4050C /* DefaultIfEmpty.swift */; }; - E15B608DD9C58C27138F0658DF39EF89 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD83661C7D461B34B59CBA67D428938E /* Errors.swift */; }; - E32D6DF371CE8D8E2519A46D4252C7A5 /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90BFC489D14E1BB573EDC77B78300C58 /* Disposable.swift */; }; - E39D71E6483501221BACD658EC4E8E2D /* CompactMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08B063219062CCBA4FC87611947A024D /* CompactMap.swift */; }; - E6A1BF57511CE77AE62E000F61A5F48F /* _RXDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = D62955DED9E7D2A6A45F30BCF5C5A8EB /* _RXDelegateProxy.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E6CE8DEF5D58911F515C3085D02B5FD5 /* DistinctUntilChanged.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26410040C396641DC2A2ABA618935E26 /* DistinctUntilChanged.swift */; }; - EA057AAB3D8A543AABA9C6BB05EA2547 /* InvocableScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95A778976F3DF4C3E0BE8CFF8FFA3DCE /* InvocableScheduledItem.swift */; }; - EAE1752C0AEDE31E5C434F36D0BD3FB9 /* AtomicInt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5574A45114B7AF48A6DE11C97987BFB6 /* AtomicInt.swift */; }; - EB276B66D2562F17B084C0D83B9D8F27 /* UISearchBar+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B344BFC1C0D14E36B199F98E6172B040 /* UISearchBar+Rx.swift */; }; - EB62DF6C85B2E9027282E1E11A0B9E9F /* Sink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06AA9C625F3E30335B298A5366E2682C /* Sink.swift */; }; - ED672A89F65EF876A81E3D7384E7BB1A /* Using.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF1EEEFAE14249E6C2D2565A94EEA04 /* Using.swift */; }; - EE0972ED958070541E8C1ABBE50AD053 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7889CA4E7E7326754FE945E78B60B4B1 /* Filter.swift */; }; - EE80E1376D7F9E22682AE05EE3054388 /* UITabBar+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94A493DBC8176AF0EE6C485A647C930F /* UITabBar+Rx.swift */; }; - F059BB2BD4F7B156353739A55AEBE2A3 /* ObservableConvertibleType+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 640E4C77D7B6E46FC569C456AF6116A8 /* ObservableConvertibleType+Driver.swift */; }; - F1DA873728D70AB358E831F18AF284ED /* RxPickerViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AE21CFC451474A9312ADDDF69FDB6D4 /* RxPickerViewDelegateProxy.swift */; }; - F219C2A0B49D73B93CEC939FEF1E7AB2 /* RxSearchControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82BA61FA49C436947F13F9CE34C37C91 /* RxSearchControllerDelegateProxy.swift */; }; - F2555054E054DE4B977C72D31968B020 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431ED4903DBAE9C89C9C0473B2E0E298 /* Zip.swift */; }; - F25C3C6D98039FCE6A01CB7484AD9D1B /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E1DA0ABC944D798284B02ACCA2ACFA /* Switch.swift */; }; - F387475B1EC3C098254F62698129B612 /* RxCocoaObjCRuntimeError+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D24118C234DAAA28D8D06D4DAED823B /* RxCocoaObjCRuntimeError+Extensions.swift */; }; - F559C7E04013E3D7F5CCE342533823DB /* CombineLatest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E452B621A51772D2378F31494E12D32 /* CombineLatest.swift */; }; - F59A01A28BA499C3731E4987D3CD8C05 /* BooleanDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D99FF3EBFFA528FACCD94484CE9C3D8E /* BooleanDisposable.swift */; }; - F63FD0F0533CAE100F1F547635F40301 /* ToArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D10FE0979AA30BC837E8945BE181EAC /* ToArray.swift */; }; - F67B050988818CB46229D1EC0860F7B4 /* PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 265DFB94C2AE7AC0DC8CB4C276047CB6 /* PrimitiveSequence.swift */; }; - F6E1B45243EF2546837B9099C53770E2 /* RxTableViewReactiveArrayDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E1283226017D88FCEDBE4D65F0E2E0B /* RxTableViewReactiveArrayDataSource.swift */; }; - F6F9C34492E47A611E31D2D63F476F13 /* ItemEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE9F2DE870FB9EA5E6080F76C2DA110 /* ItemEvents.swift */; }; - F7AC44763C0C15071FD456A0AEF1D1C9 /* Binder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 570D56F0F47A06EF81090D3C20ACC26C /* Binder.swift */; }; - F89C351693522F78C6E85B6AAF7B76C4 /* RxCollectionViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DE36FB3974AF4A9D156AC0FAEFB182C /* RxCollectionViewDataSourceType.swift */; }; - F9D01BFEF79C107A5AB6BC5E4FFDF2D7 /* DelaySubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0517049528AB1D57EE93B9528EFC5077 /* DelaySubscription.swift */; }; - FD7B95C9708C785ED9BBDF504D29C994 /* Producer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9D4D718EE79B06EF7DA68A039598B40 /* Producer.swift */; }; - FDB6B50F3AF189818D8962D74E37D552 /* RxTableViewDataSourcePrefetchingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27564198C961BEDCB7B0B8D2E04EE4B2 /* RxTableViewDataSourcePrefetchingProxy.swift */; }; - FE25BB49532E0DA3A59980FCA28F4303 /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBC4E4528155E113ADD9AACE99B80898 /* SkipUntil.swift */; }; - FE28EF50F750DD767ADFC545A6C8EC72 /* RxSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = CFBE22268708B2C3228C3D3C3F89C570 /* RxSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; - FE460145756A99E48821E2C77787C8E2 /* Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F114313913428BF0B3DF63F4A9D3128 /* Rx.swift */; }; - FEEEBA2D9A2CEAEBC53F4FBB810F0B26 /* Cancelable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B16DD2C82C26A727CDA0218AF2FB6D /* Cancelable.swift */; }; - FFDEBFF354E1D73A5836B08A98B57E82 /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = 285F374E9AFE8CE7A829816006FDEF7B /* Range.swift */; }; + 000702A76DD1A018D9B45DEB79FB505D /* UITextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B958A400ABDE65E1B6A2F557B519841D /* UITextView+Rx.swift */; }; + 005B319B494ED2DAA239B9939A504DFC /* Alamofire-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = CECE3D4B1535B76770B404D8B990A429 /* Alamofire-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 022DFEBF3DD3B5B1627278F189254A25 /* RxCocoa.swift in Sources */ = {isa = PBXBuildFile; fileRef = EBDEC0F05CE0B5F1B79334BA357E6F76 /* RxCocoa.swift */; }; + 03D894819ECA3CA8F42C578E42D08960 /* DelegateProxyType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95499D30AF1F2DE7A7CEA8AA0DBB0B3C /* DelegateProxyType.swift */; }; + 0422FC5745E406CB752E9497A2F56EA9 /* _RXKVOObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 669DDE6F99F9C873BE8B242EBA224C37 /* _RXKVOObserver.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 044B3C2F907BA92CE4BD757722963384 /* AsSingle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EAE90FF45150043BC9B9FFA197B7213 /* AsSingle.swift */; }; + 045DE6EBF9B2F63F60F5BE60C1198E06 /* RedirectHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE088314501929D3EC446CF926925ACA /* RedirectHandler.swift */; }; + 04A896288CE3A59B530250337A5F8362 /* Result+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27530937BD04E067916C314B8DA2210 /* Result+Alamofire.swift */; }; + 04B2DDDF8C3C5DAE8952E85BD4ECF6CE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD0CE05D5D076B1B5190EE5DF97FD54E /* Foundation.framework */; }; + 04B641288248D3ACC28E7F707058073B /* ObservableConvertibleType+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11D4AFEAB2754F664EEDD11730507922 /* ObservableConvertibleType+Signal.swift */; }; + 04B947DDBCF65286F1CD57A50F0F8E82 /* Using.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2934C5C2C05618A3D6A55FE1795714E0 /* Using.swift */; }; + 061EDABCC0367AF86ED8E40F3CE61BD4 /* ObservableConvertibleType+Infallible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB397BBE2053179721ACC128AC15CEA /* ObservableConvertibleType+Infallible.swift */; }; + 078C84CF59337DA8762F8C633AB70E54 /* CombineLatest+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2B74DB1EE448E983BD57207719A6ADAE /* CombineLatest+Collection.swift */; }; + 08155F3F6D55A38A07F00F85763290E7 /* UITabBarController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C184367820F49866C61F406AD3D62154 /* UITabBarController+Rx.swift */; }; + 08798AEC797123E25AFC88A5B1902455 /* PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D18BC0612ED16A755787EC28623BEA19 /* PrimitiveSequence.swift */; }; + 089BEC9E0B7F904B3970C7713A1711E5 /* PrimitiveSequence+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EE39E5285C895DFB30377387C2BC245 /* PrimitiveSequence+Zip+arity.swift */; }; + 08AE1EBFBBAB24BC410CA3DACF4C1100 /* Platform.Darwin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244E51A33CB5B29ADFE25976FDA0E00E /* Platform.Darwin.swift */; }; + 09997FDBE8364411FFB6F495729608D2 /* Driver+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3AEF057D82E1811AD90C4DE2267A79 /* Driver+Subscription.swift */; }; + 09E4A424C9A4B6AF425B42861E50E5F0 /* UIBarButtonItem+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = D96A62187B1746415E8E24F1EC2EA0E4 /* UIBarButtonItem+Rx.swift */; }; + 0AC9B1295F073079750B00AA0E6C9CBF /* StartWith.swift in Sources */ = {isa = PBXBuildFile; fileRef = 482E10370BAB6DE666A35873DE1DA9AF /* StartWith.swift */; }; + 0B2165491D9E7087D8C78C7A8128A9F0 /* UISegmentedControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD714AA5F51DF464FA139BFF404A1F7 /* UISegmentedControl+Rx.swift */; }; + 0CDDAC93C6BB582C0911153CC0C77713 /* ObservableType+PrimitiveSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F31A302B3F3DC88ABBBAEBC47911DF /* ObservableType+PrimitiveSequence.swift */; }; + 0D56320304D2381978200C77A901F12F /* Sink.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD15E723F2844714489FFB45590ABD63 /* Sink.swift */; }; + 0D7B6FF8C492D77C003609B68CFABA1E /* UISearchController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = A18BC45336950B8C433FD02E847AD38F /* UISearchController+Rx.swift */; }; + 0F4037DBF307AC8058BD0A3D35C7E7E9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD0CE05D5D076B1B5190EE5DF97FD54E /* Foundation.framework */; }; + 0F75B8C82523266A3DF606A5974073AA /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = F534EAD3C0BE78520779A2B1FA5E46B6 /* Platform.Linux.swift */; }; + 11612E8356B8DEAD493E031966EB7E1A /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BF685D4B1DD3AC80C1A61C3A326CDD /* Switch.swift */; }; + 11DDE893107A616B0CF871914526BB29 /* RefCountDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B001EE5D9F141B15F1B524D9D1CE6FF5 /* RefCountDisposable.swift */; }; + 11FC6A5EEDB9F31A8BB02ABBDF67CC4D /* ConcurrentDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DCC34277014CFA748F33D63F2B0DDBC /* ConcurrentDispatchQueueScheduler.swift */; }; + 120765129F415ACB32122F4F5773E494 /* DistinctUntilChanged.swift in Sources */ = {isa = PBXBuildFile; fileRef = B918B07799B36CAEBE63F7D83D7839D5 /* DistinctUntilChanged.swift */; }; + 134FD4E988EB8113AD19EAD10F2B07E9 /* SynchronizedOnType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CFB93251A99DD08018B991E538ADD37 /* SynchronizedOnType.swift */; }; + 142A47FCA4C5D1BB72B039C574ED50A7 /* ScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7033B5BDCF5E1938C2218057A72A2ACD /* ScheduledItem.swift */; }; + 14D048F0762E69A25CBB773E84C1CDCE /* ObserverType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7E8F79E7DC88DEB6DFACA82D883EE9E /* ObserverType.swift */; }; + 14D2C2DC6532CC4AAD73F205B9211DB8 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 953C63177619AB342C34EEE783C81EF8 /* RecursiveLock.swift */; }; + 155D953401DF644E75F2ACE729D00DF2 /* Infallible+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77B8D452A0987A391C116266CC693A6F /* Infallible+Bind.swift */; }; + 15D5D77E68C8B6AF20B7056602F7AEBF /* RxPickerViewAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41A8370357890336F08FB952BD79117F /* RxPickerViewAdapter.swift */; }; + 161856AC63FAA2C3D8164A7500E14CB8 /* UITableView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AC71F58A210A9BF7B75395A077BCF53 /* UITableView+Rx.swift */; }; + 16A880061B451E53F8D83C75110D2E69 /* Never.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D9788DA7EEE3354ABA2E15C9D71728 /* Never.swift */; }; + 16EB1EAEF9D5FF0D6E4B221ECB397D63 /* RxCollectionViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 732036B3E5DD047637BB1B9A777EA1E5 /* RxCollectionViewDataSourceProxy.swift */; }; + 171A21B0155EA10267C1DE165A6E1500 /* NSButton+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF8D4F77B2D4B21FADE9F4BFA0F45B9 /* NSButton+Rx.swift */; }; + 17E407500F471F7253C1EBBE28BABC25 /* First.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75194C640C0A0483CC26C0CFC3517506 /* First.swift */; }; + 185D79F9660F74FE0DDAF3EE71098AE5 /* ImmediateSchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 257DE2F860194DE5AA9E2B2782DF8793 /* ImmediateSchedulerType.swift */; }; + 1976BB7D7E26A12E29283E71154B63B3 /* SessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581BAF255A6D18A23D9B2B8586160060 /* SessionDelegate.swift */; }; + 1AD93376D403A851F152D1B804F7BFC0 /* Signal+Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = F747BF73A3B693E20F3184D9ED742B82 /* Signal+Subscription.swift */; }; + 1AF3BF0EDE10F429386594F787838C1B /* _RX.h in Headers */ = {isa = PBXBuildFile; fileRef = 057F21FAE790F4DD0A18A93296D0A71E /* _RX.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1B402AACD54B2064A7BC86857F2769DD /* InfiniteSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64A208A052C3CE6C1240B092E490CAB1 /* InfiniteSequence.swift */; }; + 1E45F13782B6B44884328DC493C1CB26 /* VirtualTimeScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E5E4F2BCD53E7623C2C55EA38378DD /* VirtualTimeScheduler.swift */; }; + 1E9033562EACB851BBAB74F033194B48 /* RxPickerViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63E36BC902C9ADA7FE3C6397491B5082 /* RxPickerViewDataSourceType.swift */; }; + 1E95C7EABB9F919C737C4572CF01E9CA /* Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFDC49E2EA080C69C9A651D20A8D625C /* Create.swift */; }; + 1EE44196E7BCE57AD96A2C751651EF40 /* AlamofireExtended.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFAFE2B7445F5066808C50D6442C72C /* AlamofireExtended.swift */; }; + 210E6BE763C894C38888F5B166A2EA64 /* PublishRelay+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B476816821E0315922ED7A6B7540AFB3 /* PublishRelay+Signal.swift */; }; + 21B7E9948690429E1F56EDA38B717A2C /* Pods-Instagram-Clone-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4894F90605FBEA7B041ED3C5E033C0EC /* Pods-Instagram-Clone-dummy.m */; }; + 238C4A1EC8BA1D3A575ADA67F68CD09C /* ControlTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D8E35604B9593285F8880155599FE4F /* ControlTarget.swift */; }; + 23D26111AAAA97350CE0A0C0B9A66823 /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CAA0879259D2329E9EE3AB59EE9202D /* DispatchQueue+Extensions.swift */; }; + 24C44D889CCC3570C277EB1C3CE505F4 /* UIButton+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0804998A043E63BCF0404A778DEE29D8 /* UIButton+Rx.swift */; }; + 258C51B954DEA64AD604A62BDE522842 /* ReplayRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7D0DE84DEAC2C941CAF698E76580EB /* ReplayRelay.swift */; }; + 26043B9FF33DCA7D59F1DCDBD425F2E3 /* HistoricalSchedulerTimeConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 593ECDF08EB42221F442B0B0BA4E09EB /* HistoricalSchedulerTimeConverter.swift */; }; + 26DDC1A34DD94CA11120FD2EC22FFE4D /* DisposeBag.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2FCE9EFC6B4AF321E0972F36214AFF /* DisposeBag.swift */; }; + 2722C9B25CF57D3AE89825729DEA9BED /* DelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 237C88B64E2FC4D82877BD5916785674 /* DelegateProxy.swift */; }; + 272399005DD92F08084869CB8C955A97 /* RecursiveScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E8ED230B0233D8CA891E48B052C4E8 /* RecursiveScheduler.swift */; }; + 2804E6D768D9F7A9A4D0DFA9C4C947CD /* ConnectableObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132F36A02348DB3BCDBDACFEF9CB787A /* ConnectableObservableType.swift */; }; + 28AC98B2CADD31F0868D4AF4979E9FD2 /* PublishRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1BC592E13CDF07E2B7ECDFED477DC79 /* PublishRelay.swift */; }; + 28D5D9EEAE845C76C8079BD1C77BFE82 /* RxCollectionViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B286A5673B1B7539EAE7FB20F57F746 /* RxCollectionViewDelegateProxy.swift */; }; + 28DDBE36EE067086F4925C830D668FBA /* KVORepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DBD5C098129C5A899245FCFCFE90F2 /* KVORepresentable.swift */; }; + 291212C7E7B0846DE4EE715CEE2D7A18 /* Scan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D762331D58A21757B046C90540486FC /* Scan.swift */; }; + 29A045F0798283EAD8863A575B5A18FC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD0CE05D5D076B1B5190EE5DF97FD54E /* Foundation.framework */; }; + 2A14C75617DF21ED981690C05AED614E /* WithLatestFrom.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC3BE7AF4B17BE5C089702D819FCC4D /* WithLatestFrom.swift */; }; + 2A76C0C87BECC7444FA23FE5FF39A487 /* DisposeBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD704C7FD77889B382D1881BE82B57CA /* DisposeBase.swift */; }; + 2B82281C44FE73DE8D962123E0DB9587 /* BinaryDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD75294A445E2D81BD626118984385FA /* BinaryDisposable.swift */; }; + 2BC5CE923B1642BD1D819DF33B4B3710 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E96DDF40C7F94101633F7E4244996BF6 /* Utils.swift */; }; + 2C64E385669A619F264F7556914DF205 /* UISlider+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC23ED6D414C352E57C88DC42A6022F /* UISlider+Rx.swift */; }; + 2C6ABD95B263C08BA54FD26E7EDFECE1 /* AnyObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = F344AD341770313494511A6FC34CD7F9 /* AnyObserver.swift */; }; + 2CBE3651CA006E19F5D64A2DE9B9A028 /* CachedResponseHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F65EFD9FCE2C86F5C16EF6707DAEE01A /* CachedResponseHandler.swift */; }; + 2CCD13099063CD560E3067BD132914FA /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44621BE174840A776DA54345ED8C22F6 /* Notifications.swift */; }; + 2D05B426216B69D767ECB8145CE4B4E2 /* RetryWhen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63E8E04E3E7BD0E30508D61F734DFC14 /* RetryWhen.swift */; }; + 2D7A33D35011E2763FF5650BCE8705C0 /* CurrentThreadScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46AE8C1E9DACE1C8DDBD6126304A9EE5 /* CurrentThreadScheduler.swift */; }; + 2DD61C8CDBF0EC6C41F8484607616242 /* Infallible+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1013EB27F868D358C47ED382D6D4F89 /* Infallible+Operators.swift */; }; + 31F0D187BC76DAB3C2DEE8B2CABB0535 /* RxTableViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84F1DF9E3AB5F5CF0D39D814F75A4F5 /* RxTableViewDelegateProxy.swift */; }; + 33A7D0F2D03004CE256A75E03DF33C70 /* RetryPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7918FA9555E6D24F7C7C37B53D3FC5 /* RetryPolicy.swift */; }; + 3440AB5A3A26F7706143726E7B6CFD41 /* CompositeDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F945667BC8F068155D11033D255A3993 /* CompositeDisposable.swift */; }; + 3496CF128687DF8E8649A8BA79C923D4 /* DelaySubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0424BF5445C2DE265C48275A088BD3C0 /* DelaySubscription.swift */; }; + 350A88CD380253A5239CAA47B5C78EC7 /* ReplaySubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF053478C3D4A12F08977D089A9185F /* ReplaySubject.swift */; }; + 35F188D95219806671DFF0A26805E7EE /* Delay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8D740B9CD39CEBBE02FD72043BA317 /* Delay.swift */; }; + 3685C88CA5F36F4170E84DD0227D244A /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 565261C7427A20C48DEEE1D949EBD371 /* Bag.swift */; }; + 38D0534EDDC37793282AD797DF3CF4B0 /* Observable+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = C89AAA90232D76CB06DD77296FE8745B /* Observable+Bind.swift */; }; + 397B37B379C8A6D905381B8F5E18F391 /* Sample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70932FD1797B63C347443B74252917E8 /* Sample.swift */; }; + 3AFEA39C21C700AAB86C4ACD9436D357 /* RxCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = B961666FBD681C6B13B784C18D575465 /* RxCocoa.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3B82FB00AD02652E1801233E5684DB1D /* NSControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31FC37E7C3FDBAA92A3B8F8C6E840F31 /* NSControl+Rx.swift */; }; + 3BDE15405AF6942A6BDFBC25EC869206 /* DispatchQueueConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C57355D0496F6CA05BD3B095F859BF67 /* DispatchQueueConfiguration.swift */; }; + 3C4059621E23842C19D4EB5D35B41989 /* Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20C5AA8122AA25F6AE43D02B1AB787B4 /* Validation.swift */; }; + 3C456A929F009FB2A87D084E6A04D227 /* Infallible+Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F3AD1EC697290EA4E4FAC118C308D98 /* Infallible+Zip+arity.swift */; }; + 3D42C9D3EEBE1EAD7E365276753FE99E /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FF1808BD217AC51DBC0323F10A5641 /* Queue.swift */; }; + 3D445FD9D8FFBDD79E0D04BDFE96B0BB /* Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C233162E224D042B1A9ADB5FFC75596 /* Signal.swift */; }; + 3DD9694A6D1F5035C6C400C6912B9E36 /* RxCollectionViewReactiveArrayDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF920294818B5015C2A432741B8449ED /* RxCollectionViewReactiveArrayDataSource.swift */; }; + 3EC3D62A64883A9AE11396EB7C84206E /* AsMaybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = D946CD415A40593F4E87F434B15FBFB3 /* AsMaybe.swift */; }; + 3F16037EF959D92481B4E5CAB91983A2 /* DefaultIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A528F662FE12267714BB9BD1308F560 /* DefaultIfEmpty.swift */; }; + 420C68A3D27F8DE314301669960F66D2 /* Zip+Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431CE5CA440EADE478463371D8940E0F /* Zip+Collection.swift */; }; + 442F99A1D4DBDCC3EE4D650936065479 /* Empty.swift in Sources */ = {isa = PBXBuildFile; fileRef = F708BA46014EA7CCCE42123E340788AB /* Empty.swift */; }; + 44AEBB2D29B9FB87530556A0CEC170F7 /* RxNavigationControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCCF0F617B295E0168704E10183E07A /* RxNavigationControllerDelegateProxy.swift */; }; + 468F4F96FF17FA2109E912945E6ADDD5 /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D165677590A732F5E46A334914AF9F1 /* Range.swift */; }; + 46A64A43AFA057B6B63C8F0C12F509B4 /* Combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA0FDF7B29DB45C9207791DA9305107 /* Combine.swift */; }; + 4718D5DB01C595629D6E05136B3ECC88 /* Throttle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 10683973D347C94E5EAFC16D41AFD67E /* Throttle.swift */; }; + 47B48B7531CE161773DEF0B851D08037 /* ControlProperty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5296303E7B76C7C449D2CC7E0E000281 /* ControlProperty.swift */; }; + 4838B3C8759DACF738F61BF91100379A /* RxTabBarDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6591215365055B0134F330A97A10C301 /* RxTabBarDelegateProxy.swift */; }; + 4878A6C8BDEF6FCC155719CA93BA9586 /* _RXDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 71C3768A32C06D82A80CB88CF8751FFB /* _RXDelegateProxy.m */; }; + 493127C2F29206E39BABF0F5EEBE3E66 /* OperationQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8E167AE7AF784540620A299389233DC /* OperationQueueScheduler.swift */; }; + 4978F4A7A4B4ABC4A51E9F54FF6E45A9 /* Take.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662CE261C0D358E5AE55613422CCDBCB /* Take.swift */; }; + 4994F1CABB9926703D82BA0D9D66321C /* RxCocoaRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 252782DAFEE92AF927AF401D81DC4756 /* RxCocoaRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4B745396FD1223BA8532DFE2216E043C /* NSTextField+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B82686D2BD45E21F1DB076390F8B0F25 /* NSTextField+Rx.swift */; }; + 4B9E089D03AB2A9FEDE3B25BBAE206CE /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = 064F1CAB9993B8292FFC49F391E694E6 /* Error.swift */; }; + 4DA69E2BBC485752A9DD91980A109765 /* Multicast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C9BC0E9772C9C6C7981B6B3A3663C06 /* Multicast.swift */; }; + 4EB4328C78B36211BF7D50529327FD7C /* UINavigationController+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5369C855073293C39F870980BA7DA /* UINavigationController+Rx.swift */; }; + 4EE0F2D2112CE993AEA24549F5DB19BF /* UIControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0755115E5EB323278C37AC66CAAE2B1A /* UIControl+Rx.swift */; }; + 4EFD31D7DB8D26D9D031A2225A0C6AEC /* UIApplication+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1505651CC182DC052570C0F0245D640 /* UIApplication+Rx.swift */; }; + 4F744303AF9B5E7CEF8C3A9327E852B9 /* ControlEvent+Signal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7887DA93F3CD7EF16FBDAF60F9A0C6A7 /* ControlEvent+Signal.swift */; }; + 4FC27FF6DF0328A134393A57E735977B /* RxTextStorageDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CA9BD79C42A139D0C8431BDFDA3223 /* RxTextStorageDelegateProxy.swift */; }; + 50681D70D26BA315A5DDC1365B4CF0BB /* KVORepresentable+CoreGraphics.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0C41ED95427AF71D36B4F084BE5A6AE /* KVORepresentable+CoreGraphics.swift */; }; + 51C984425C777CF8B613C230DCE2DB65 /* UIGestureRecognizer+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EACE9FD0C33F1B6B27CC836BDBE706 /* UIGestureRecognizer+Rx.swift */; }; + 522A41C059E5B3C6C02DF4A3C2E4511E /* Disposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E371A1CF57F9459FCB12BC146AF7E84 /* Disposable.swift */; }; + 5291A92FB6C7E3FB265DC22EDD908884 /* Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 623EBC29B18495CA0C436D827CEE6728 /* Driver.swift */; }; + 529BDA5E8CE104C4B384017447D0DC60 /* _RXObjCRuntime.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F365E68BF9F85C934803EEE843C7507 /* _RXObjCRuntime.m */; }; + 532A9D1C9C53318F736994B5DA9AA3A3 /* SkipUntil.swift in Sources */ = {isa = PBXBuildFile; fileRef = F153DE82AECB4A5F740D245E96EBFDBF /* SkipUntil.swift */; }; + 5406B893BC83767F08861921012B4659 /* Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 20BC4B195BA7EB8AF77DA60381FCCD43 /* Timeout.swift */; }; + 548B9145185925F281D9B1951379E6D1 /* RxTabBarControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366AB29585827B22DA277DCC64C6210D /* RxTabBarControllerDelegateProxy.swift */; }; + 55AABB1FB38F61A3369ACC555FF3046D /* Alamofire-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 22AAD42AC2A848D8F7BFEFB4DC3A8879 /* Alamofire-dummy.m */; }; + 5650EE6C7E606AE6BF10761F90BB045C /* GroupBy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 003BE23129F6FB245F50432D5F89E24B /* GroupBy.swift */; }; + 57168D708E9521362A4F4B59AD82FB1C /* Enumerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = D658D77B0412C8504611038D50C9B8DC /* Enumerated.swift */; }; + 594A8689EFB607611557F8BD05521C3B /* Repeat.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE5F5D65B6D06DECF5638D0B4908DC4F /* Repeat.swift */; }; + 59691189B7A014BB0230561AC0A489A6 /* RxCocoa-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 93DB2AFE7188A1E1A53B376DF03ED898 /* RxCocoa-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5A6440D152055824959434874F2D583C /* SingleAsync.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F9933EF3E2D0E5C9A38450DA95C940 /* SingleAsync.swift */; }; + 5B58B8650A9AE15A40EA145EBFBD4FE5 /* SingleAssignmentDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 716C98F332A803D36F35817F3A5E10ED /* SingleAssignmentDisposable.swift */; }; + 5C43178561F518739BB1B49DA976DF7B /* ObservableConvertibleType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81A38A41FF433485F61118C92056AB27 /* ObservableConvertibleType.swift */; }; + 5CB7453A3225B8F762D666500654783F /* PublishSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 801EA459B5D61FCD65C817EB048EAB29 /* PublishSubject.swift */; }; + 5FF9F855ABBFE05AD568D40398E8790D /* AnonymousDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D37F407A84623FAB151F7CA5CCE94054 /* AnonymousDisposable.swift */; }; + 6466998AAB36640368F482091316EBF6 /* AsyncLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B86CA8FB56D594D41CF699D266A6FBE /* AsyncLock.swift */; }; + 6604D3F29241ADE4132FB184EE7AC42A /* Merge.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C8550C0F6D06103D8A56924D191475 /* Merge.swift */; }; + 68623BC382EACE93D53213D1D5AAAD3C /* NSTextView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2AB38E402838475B1BDA2DE7834D96B /* NSTextView+Rx.swift */; }; + 68FB2DCB4C77DBCAF9A6037E470F2BDE /* ParameterEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B20B9F6EB6E0D8B0DCE2E0A406D8986 /* ParameterEncoding.swift */; }; + 69537EEBAEE542798C9630CB8F96DF8D /* NotificationCenter+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EE8D25372CE963CE58F7C2F4FB187CF /* NotificationCenter+Rx.swift */; }; + 6B26A5BF0DAF24259CD2BBD52A8C936A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD0CE05D5D076B1B5190EE5DF97FD54E /* Foundation.framework */; }; + 6CA34295D3627D8159E4CB8C18DEEFF9 /* TakeLast.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC0D711F5C8019E955B578378608C5D1 /* TakeLast.swift */; }; + 6D8CDC66C950346874056F3F45FAB0FC /* NSView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAD641B0D7B200397821BB739A168DD1 /* NSView+Rx.swift */; }; + 7016FD62B55A814DB246B3286CEB44A2 /* AddRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923E4FEB8C92DE3B193F1BEFF1FAFA36 /* AddRef.swift */; }; + 7024A2E9D2A76033F9F524AD94256D55 /* CombineLatest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2BF8546CFD71D9F507D96AF1C570539 /* CombineLatest.swift */; }; + 70527867C4C4C965053E4283F3778986 /* RxCocoa-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F538C639AC1945189EB1CE26FAC6BEF /* RxCocoa-dummy.m */; }; + 70A41125865DDF878FC4CBD646349805 /* UIScrollView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44B8E99A079E190217E678B7AAFC79DA /* UIScrollView+Rx.swift */; }; + 71D5BDF4D210C1DC54AB197B1D2E9D13 /* ControlEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2798ACEB5A9F3BB777E6E657288583C /* ControlEvent.swift */; }; + 71D5D19E7A964BCDC00D217AAC6C6E4D /* Timer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E233119C4C85536D7158A45BC58EE2BC /* Timer.swift */; }; + 72EACA60D843947316E0D45FD074C744 /* RxMutableBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEFA60C5F16D18879D7BA1A6092A068A /* RxMutableBox.swift */; }; + 742C6177ED8662FF241782BA7334E634 /* SubjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 103354D756EEF3F7108DEC03A6165EEC /* SubjectType.swift */; }; + 7483E5327027263F7E4B94A2997191C4 /* AuthenticationInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 581CD3FDB8146C432DAD2AE38AE8596E /* AuthenticationInterceptor.swift */; }; + 75966A9262648D4647D764E3E76BC6AC /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = DED707571AA14733539CD9ED34AD9CD3 /* Response.swift */; }; + 75A6FEB218DD9F07987C72818AAD4C95 /* Platform.Linux.swift in Sources */ = {isa = PBXBuildFile; fileRef = 425614E9FB485B7AFD1395F3890AEB4F /* Platform.Linux.swift */; }; + 77319AE6A71B95F2B926B55B5C264F77 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = E95780524ED5621196640AB551C752A4 /* Zip.swift */; }; + 775B8F8F47D2D5F672D39D51ED962DDB /* Infallible+Create.swift in Sources */ = {isa = PBXBuildFile; fileRef = 852B8D3959EFB94CF388478FD427AA2C /* Infallible+Create.swift */; }; + 7930C94414B4C661867AC4FBE82E996C /* URLEncodedFormEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B6565DBDAB6E638F9B180AC2B084B0E /* URLEncodedFormEncoder.swift */; }; + 7A243B952653A37D1AF93122D3BBCAFD /* Maybe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17878B482853B987E43D970E0F91E0B5 /* Maybe.swift */; }; + 7B068137A8925891446203B5D3D6A4ED /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D3D57353834825F7B52B816066B7789 /* CFNetwork.framework */; }; + 7BEF420E8F9099C5079845A9BE4DCA63 /* RxWKNavigationDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 004BA208237B4E16EA699ACADC85AFE0 /* RxWKNavigationDelegateProxy.swift */; }; + 7C0DC741562A17F09F60EB9329DDA7CD /* ControlEvent+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B6C10B0C5FCC12A649E8403532674 /* ControlEvent+Driver.swift */; }; + 7CE78060DC2CC6D444FBE6966914134C /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 557F4A5C3A1E88463A559F6771708562 /* Filter.swift */; }; + 7D5C429450288B43FFDE26CFDD7BECB2 /* Dematerialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = DECFD6204777ED86D3E84F3EFEAEE6C0 /* Dematerialize.swift */; }; + 7E02F5B62BE00E97847DF549FFED2490 /* HTTPHeaders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ECFFF39AC84FF510A575BBBD6BA4B0A /* HTTPHeaders.swift */; }; + 7E3402342205B2DC03468A7FD95F61A9 /* NSTextStorage+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8096FEBA479025EB40840B0CC6BD31E /* NSTextStorage+Rx.swift */; }; + 7EEED39CE5F3611AB4D7205FD038021E /* NSObject+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = D913C2691FF84A8A5E872398995AC7F6 /* NSObject+Rx.swift */; }; + 7F1BB526AAE3ECDCE90127D9D0E10261 /* StringEncoding+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EB486C2DC92FC85AE2811D80085646E /* StringEncoding+Alamofire.swift */; }; + 7F60B371FE78073E7DFDD621FFC482CE /* URLSession+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 86E5EFE7C6AF249A0542C9D41215F5FE /* URLSession+Rx.swift */; }; + 7FE695DA8EE7FF1286556E06B692009B /* MultipartFormData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FC6857CE4BA0536407B134EE1028C0D /* MultipartFormData.swift */; }; + 808C960C82D708FC1A42C581D6CB4940 /* URLSessionConfiguration+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BA8073424D0DF7ECECDDB2EF816A68 /* URLSessionConfiguration+Alamofire.swift */; }; + 81095C6CBB8956AF79E33BCE939AFC2D /* ConcurrentMainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50813D9A78FAA9D509BC9BB9B2F3C28E /* ConcurrentMainScheduler.swift */; }; + 81A394201D240F032A6108ED479B427A /* UITextField+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26C3823CD02898688DB8C4C27D6F1450 /* UITextField+Rx.swift */; }; + 81B8D2B7CEB25C2448B0BC9B33591A65 /* Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3126D57CF6D0BC79B9BD8D382FDFF41F /* Session.swift */; }; + 824D816B1EE404F2DD400EE678695CBE /* ResponseSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D89AF9F1C03B2EA8FBCB02834E6E7DB9 /* ResponseSerialization.swift */; }; + 841FBD1EB10F9112D309BB28BD10CF1D /* SharedSequence+Operators+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844031D7991F5389D65BF8E22D318F9D /* SharedSequence+Operators+arity.swift */; }; + 847EBE58CCA654734197C7384E7B4094 /* BooleanDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39BFF1F4303B0AE6E2D295DD49C76DC2 /* BooleanDisposable.swift */; }; + 8540FFA5EAC0F99F641A2F0D4C164917 /* AsyncSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF5C52B068668E86B1D259B8C141CBE7 /* AsyncSubject.swift */; }; + 893252F553C133D865FA1BD98D08881F /* Cancelable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07BFF01DC46CE2B8775DB7C2333A4181 /* Cancelable.swift */; }; + 894BF76C4272C38C9E17385110BF4A41 /* _RXKVOObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 94E20CB67BEF87997F5C88B67D4165B1 /* _RXKVOObserver.m */; }; + 898842972F3799802AAB201F84B8CA39 /* AtomicInt.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF03C202E24C0B84A8025CA0E8FFFDBC /* AtomicInt.swift */; }; + 8AEF0775CDF920AC2DBE0C725B59EC96 /* UIStepper+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA1896E16598842002E1E264F719366E /* UIStepper+Rx.swift */; }; + 8B7686A732E13434E997809196B15955 /* UIRefreshControl+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87BB95834BDD56A6F6615F57EA3B47D /* UIRefreshControl+Rx.swift */; }; + 8D351E59580B8F5EA4D1F1E9C926608F /* RxSwift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = B5B304BD966D13EF655D5CC30AF30CB3 /* RxSwift-dummy.m */; }; + 8D75FC8D7476C9674234F39F1A820D8C /* URLConvertible+URLRequestConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CADC59F472FDD873ECC8AC0334ADF3 /* URLConvertible+URLRequestConvertible.swift */; }; + 8EA5CC7EF28B004A8A813925E4F17F93 /* WKWebView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011724A1A671D7E12ABD37BC873AE4BA /* WKWebView+Rx.swift */; }; + 8FE0BD68EA39B931E49D9C038BE80B65 /* UIDatePicker+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDED6E55DC07C9A13486397B32A789B8 /* UIDatePicker+Rx.swift */; }; + 900441C94889A5857E6A62ED130645E1 /* Producer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F43B8F01A543777B15BE6850ED311C5 /* Producer.swift */; }; + 90E87249660F4D3321E01F0F075095CC /* HistoricalScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C710A6E5E7103CF26BF6DA1A3665A55 /* HistoricalScheduler.swift */; }; + 9166043CED65CDD457AF559A9B127E17 /* BehaviorSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = B63E8E74CB465ACEDD8871E750E708C5 /* BehaviorSubject.swift */; }; + 938B46EF411204D0BEE0A56A7D584D51 /* RxCollectionViewDataSourcePrefetchingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56BCC58210173BBB48CBEEEA55B9A8AC /* RxCollectionViewDataSourcePrefetchingProxy.swift */; }; + 93E36BBF7E4EA867F3301D79C1BC378E /* Amb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43CF235C9231F1361CBDDE0EC92FA624 /* Amb.swift */; }; + 945DBBCB62542CD24B29F83FAFEF13B1 /* NSObject+Rx+KVORepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17E9145798CDAECA8E6048A90E9D4748 /* NSObject+Rx+KVORepresentable.swift */; }; + 95181366D610146E29AD34636DB9EFB7 /* Platform.Darwin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8105F1AED97EBB31E9ECE90220331050 /* Platform.Darwin.swift */; }; + 963BD25D8D11DE9D03732937C7CA5FB3 /* Completable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CA391017BD2A3678044F22FCDCC8E74 /* Completable.swift */; }; + 966FD99CF015E0E1DE82724BEBAF6F47 /* BehaviorRelay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DFCC0632F76CF0BA9C49B9A2B33DF57 /* BehaviorRelay.swift */; }; + 9850A80051F5259DF4BD9060DEFE783F /* BehaviorRelay+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A3DD3E4A9A4673B47D4C6BB1ECC2FE8 /* BehaviorRelay+Driver.swift */; }; + 9872BA71E352EE554FB705FBCDAA3C40 /* Sequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CAE89435EE2619F199768480BA9B3AC /* Sequence.swift */; }; + 9881194F4BA84B4F860B816C911C90FE /* TakeWithPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CCC4722D47EFB9F36D15D6075781DB /* TakeWithPredicate.swift */; }; + 99D058E53EFEE3AC4857CDE3DBA5C004 /* ParameterEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97A8FF5FA28E690E10D289E1D57F7930 /* ParameterEncoder.swift */; }; + 9A658600907098820AE61B00B7A0FEA0 /* Materialize.swift in Sources */ = {isa = PBXBuildFile; fileRef = D23F046BFB31018CD45DF786AA3F3152 /* Materialize.swift */; }; + 9B6D684A7CCF9470B92E10267E3987CA /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4258692E67A0CB362F7BB3D91413B26 /* DispatchQueue+Extensions.swift */; }; + 9C9030DEDB0DF955B16FE08C50892D57 /* Concurrency.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B62EC386D75F6A3C259E3A603A4CF8 /* Concurrency.swift */; }; + 9DB4A288E7875E7346EAB537875222D8 /* SharedSequence+Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011C15D0AD92913A044FD01816592922 /* SharedSequence+Operators.swift */; }; + 9F497DACD3A261A4940D09D7A68C8C8C /* Catch.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF1E3D9A965EAC45B9F4E268B89C23F7 /* Catch.swift */; }; + A00B02753121E48F19A40E0AA234F27F /* GroupedObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F36285EAC13EEE1ECCF3F9D7FD36466 /* GroupedObservable.swift */; }; + A09269702D45FA71B146BBDE37571325 /* RxRelay-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 46E3B0C82A8F4E4AF7951C604C8D41F8 /* RxRelay-dummy.m */; }; + A1194BE78FCE2929CDA65C95CA310EAF /* RxPickerViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 256B92342A5164F30F9289C7D50E5A6C /* RxPickerViewDataSourceProxy.swift */; }; + A1985C2CC5030AB984FFA33B94E1E39D /* ControlProperty+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A75C1BA7C53C89CFEF1F83EE37E7EE6 /* ControlProperty+Driver.swift */; }; + A1A1FF8C15D79B3C9ED0121FE1642000 /* ScheduledItemType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C260175CDEEFDC2E0924E1EC569B22CB /* ScheduledItemType.swift */; }; + A29100AA1876DDEFF6F54694A51FDB0E /* NetworkReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F1BCE55561F2EDA941C3A3A1284DC55 /* NetworkReachabilityManager.swift */; }; + A2F7FF2AEFF21D78671543FA8CB6A8B3 /* NSObject+Rx+RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B417BFB59BD825253EAED7DD8806D519 /* NSObject+Rx+RawRepresentable.swift */; }; + A32E5E2F188BE43B5A81403FD909D832 /* SynchronizedDisposeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F577F1C935B3E560C16CE20C6521266B /* SynchronizedDisposeType.swift */; }; + A3330962182718216DA19E8F8F5C585C /* Binder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F67F863AAD2C0C759AC4DCDA316297A5 /* Binder.swift */; }; + A3423ADEDFB20D72E2C608221A26D3C6 /* UICollectionView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83EE95F979FACA89F44D68CC3489DE8F /* UICollectionView+Rx.swift */; }; + A35821CCB39160451DFA5C1E1D95D283 /* NopDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7269D3077B11B2C74F5650E6D52258ED /* NopDisposable.swift */; }; + A37D3661369446F3AA978C8FD342A83A /* UIActivityIndicatorView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C193EEDF6B5EBAB9D21CA69760F3160 /* UIActivityIndicatorView+Rx.swift */; }; + A435E4B3FF0B326E880502C6FD3FC987 /* KVORepresentable+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D1078A15FDA40825DA0C34D1DCD56C0 /* KVORepresentable+Swift.swift */; }; + A53BDE589BDD6483F3EEDCE5EA1DCCD3 /* Protected.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3673AC5B3124EC7A5ADE41E8D4A32E38 /* Protected.swift */; }; + A842C160BF51636979E2364404DF3E30 /* Buffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5616C61981FF49AAC8EC1C8E02D6860 /* Buffer.swift */; }; + AA7BBD3390AF2ECAFA1AD576BB69CE15 /* RxScrollViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 470212E66C74D5757E37A837E2B1F0FD /* RxScrollViewDelegateProxy.swift */; }; + AB4875CA5028C3C32274EC2CCDFE9066 /* NSSlider+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012453260A0F0691E70C3944FFAF048C /* NSSlider+Rx.swift */; }; + ADC81CC0E59F09E172453DF440E97103 /* InfiniteSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03AD707277DF16D02FC728818FCA494F /* InfiniteSequence.swift */; }; + AEED75FDE3F814DF658D2F7814968377 /* SynchronizedUnsubscribeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B06E8014F3D0084CBB2E358F32E9DEFF /* SynchronizedUnsubscribeType.swift */; }; + AF745E785C247AA2081CEF2C52643BB3 /* Event.swift in Sources */ = {isa = PBXBuildFile; fileRef = 112241935E9BE9CFD251FB234B0FB839 /* Event.swift */; }; + B0243071D95B74AE6520F5901A5C54E3 /* Reactive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DAA98713A8129DA8D7F67CFEB63F07A /* Reactive.swift */; }; + B1C0A51154B2C73747A94C776622B414 /* TailRecursiveSink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5425A30F69C058EBD3CECC3192A4A455 /* TailRecursiveSink.swift */; }; + B25714FEA238E63EFCC45BF5646864B6 /* CompactMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = C53AA73242D70049D68DCA526B69D005 /* CompactMap.swift */; }; + B283E0B7BB5A5910188B1B4C7B15FF53 /* ObservableConvertibleType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F188F3631ABA83DC4520B28431AF8E1 /* ObservableConvertibleType+SharedSequence.swift */; }; + B31C49F56A9C1CFAB698384FBBAC68AF /* ObservableType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7182CF8BE4608290699B6B2CF78E388 /* ObservableType+Extensions.swift */; }; + B3621037B1B0E697C854F0FF109A594C /* Bag+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9193A575AD5A353845C82E257E9E18FB /* Bag+Rx.swift */; }; + B3658C29BBDE1033F6269A92E612CB30 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = E62DDC544E8AC865B9AA08706E6FC139 /* Request.swift */; }; + B427A8E277EDF230990C4E6BFB0896B3 /* ElementAt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B6279D00F667A0057801EF3AB863202 /* ElementAt.swift */; }; + B4D195EF46872334B240F3DF7D52A2F4 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4104B378EA3EBFE66129D192B22A2627 /* Lock.swift */; }; + B53CC742CD11968434A0A63B176A8FF6 /* InvocableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CE26D5D8DD5D6141DBE1A83DB70651F /* InvocableType.swift */; }; + B5ECDE3256892020DC7049182FF91713 /* RxRelay-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = BD18805FCE30E1005F6FC4198C5ED48E /* RxRelay-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B642FE050151439BD436A016549A5AFD /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2187E0B6C891F3F1767EE5994A0A04F1 /* Optional.swift */; }; + B6B0D29695B41D7265D9DE7E1D154405 /* Date+Dispatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F38231AE4C38080DF74A2D0BEDD8BCE /* Date+Dispatch.swift */; }; + B6D19CD2E68222A070CE0EB061FC4604 /* CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8BB59E8726483F52D6D6971BCC1B3B8 /* CombineLatest+arity.swift */; }; + B704B198B9B520D449260877E300D821 /* ServerTrustEvaluation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA8EBC7BECC7DD0598F14332FCC97995 /* ServerTrustEvaluation.swift */; }; + B7A2022F7043A3980995817804825B79 /* Pods-Instagram-Clone-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = C4E2F629E6629BB14C3AA2C13A4D05EE /* Pods-Instagram-Clone-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B7B2D2BA017F31692A03052861B7A5B3 /* InvocableScheduledItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 730E778D74EC5F08A80D328E71B9589A /* InvocableScheduledItem.swift */; }; + B87E54A6A887700FD31379C0C6AE709C /* Skip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C890F215AF0CB31979E34F7A9F3B85C /* Skip.swift */; }; + B8E27E8D24CBE6DB22F38E06FFBDB710 /* _RX.m in Sources */ = {isa = PBXBuildFile; fileRef = D86EDF0C7FC833194B4391F2E04A1DC8 /* _RX.m */; }; + B9F08FA7D76F3520EC5AA58987532DD3 /* ObserveOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 56060B7A57AAEBE6E3946AA4BD3854D5 /* ObserveOn.swift */; }; + BA2A348ADCA09F37B08F8C354CB4363A /* ToArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33B20AE498859D4D4AF71FD9B168684F /* ToArray.swift */; }; + BB75BCF76F22254E3302085A5A6A4B48 /* SchedulerType+SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D6619DD182B507FB857AD61304B44 /* SchedulerType+SharedSequence.swift */; }; + BC0ECA8F22DEDE8886E189CD0EAA1197 /* URLRequest+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734C97C73C262E10D878B235A0B0B183 /* URLRequest+Alamofire.swift */; }; + BE5B281805F9991E38CA52CC2E365CA8 /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 267DB70A0C2AB28FC178E80A0718B8AB /* PriorityQueue.swift */; }; + BEFE617EABAE8B434A580CCD4179C04E /* TextInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = B766558A6AFFF5D989A09741CD470BA7 /* TextInput.swift */; }; + BF73656CDE078B545CD5F4AEA5A038FC /* RxSwift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = D83242FBC909C2DC4C102061C1D985C7 /* RxSwift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C0DCA1EC7FD3E2AB3023238F1DAEF1C2 /* Do.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0640980150BB98AE63D6937157CEB1C8 /* Do.swift */; }; + C476A90BE4CFB2515507AC4B72DCB36B /* Debounce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 871FB5539265859CC8CC49821EC0DE38 /* Debounce.swift */; }; + C4D350D569A2B6567E087ED515A93EE2 /* RxTableViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F4EC36A54010622D3E1DBAF1CE07365 /* RxTableViewDataSourceType.swift */; }; + C4D3565A73D43F43B237AA3B63730B5C /* SwitchIfEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35BF645AE8BDB43F5F91AA91349F1B63 /* SwitchIfEmpty.swift */; }; + C56A14C84CF05A1A96D8B92E16E0CBFB /* SectionedViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12427AF8DF82101B9D78DAB0E6F28AAA /* SectionedViewDataSourceType.swift */; }; + C6272C72012F7E61389660D757E69377 /* ShareReplayScope.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70ECF0CFF0163ADABFC3B6C7D328962 /* ShareReplayScope.swift */; }; + C66AB81E05FBA6BA810072DEB7D45EE5 /* Observable+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0367676A099A476FEA0C5CB232616A22 /* Observable+Bind.swift */; }; + C66C4E3E67C26B960FABBC8F1B0C056A /* RxTextViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 171C5F87CB9880D7A87F28226F3A2966 /* RxTextViewDelegateProxy.swift */; }; + C94188E1E8D5A6222FE10E1324FD7241 /* Reduce.swift in Sources */ = {isa = PBXBuildFile; fileRef = 993CAA60E070CF39B9426C3F90BD63E3 /* Reduce.swift */; }; + C9FB700EA3EFA40792CC5E6344EA4A9A /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57446328CADAB2C557D69630490DD5BD /* Map.swift */; }; + C9FBDF5C0881490E629EACD2928ADF11 /* Infallible+CombineLatest+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DE5128DFD130806F20EC429CA451C0C /* Infallible+CombineLatest+arity.swift */; }; + CA0C80FE14246281AF85FA8898C5D7BA /* SchedulerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90437FAB08E287AE379C7C8CFACED79F /* SchedulerType.swift */; }; + CA38E66DD2A16B2C3BF0B871AE215D6B /* Completable+AndThen.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC17AA237A1B658AD0238FD93F0DFD62 /* Completable+AndThen.swift */; }; + CA7E6313F023439E2D6C9801EB6202A7 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2BFEA63DFDBE33D8A71974A9D6C7CEC /* Observable.swift */; }; + CAD49B3D93412E69BE3DADA23B31941A /* Deferred.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7FBC5DD60EF61D351B0CA282AA2987E /* Deferred.swift */; }; + CD67D7019DCA2D8C5AA2842C0E0BD695 /* SerialDispatchQueueScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = D514C0BFAF080B34155E84CCBC3F2AD7 /* SerialDispatchQueueScheduler.swift */; }; + CEBFFEED65D877702B2F36102528CF6D /* EventMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CD6F37FF01714E62B05CCE204A180FE /* EventMonitor.swift */; }; + CF9DAAEC618DE435A7DF19579DE30AA2 /* PriorityQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB37CF81A092A3E976BE535DB38A6964 /* PriorityQueue.swift */; }; + CFCC48239D82DEAB7B3541A59C7F439D /* AnonymousObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41F27E716EA312BE508938A789401C98 /* AnonymousObserver.swift */; }; + D05116642C20C568B926B4025B6EF995 /* UISwitch+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C41B899C63FF345426E1B52A8A627AF6 /* UISwitch+Rx.swift */; }; + D0EA90FBF83350C49E6EF6C8A98D6F00 /* AFError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CE9464205009D39C62EE5E3B85E6260 /* AFError.swift */; }; + D12C55FCA09B4EDB39F53C873CC9CA47 /* Decode.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD8422862D3A378F92CAE72A63E771CC /* Decode.swift */; }; + D1DE14077A54174F00E887101A48AE8A /* RxTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 768133F2C2CC8674F7220CD20CBC738C /* RxTarget.swift */; }; + D3FEDFC5BAE7D0A94414C4230E2B363E /* Just.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E48048F9DE3CE9CDFD07D96C43092EB /* Just.swift */; }; + D583F8FC3BFE7CE7368F5FE75679F388 /* RxTableViewDataSourceProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A218B60A6F3B33C317DFF65DD678205 /* RxTableViewDataSourceProxy.swift */; }; + D5B24C3951015F77332C0119C80F312F /* VirtualTimeConverterType.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9F6C121115219E23559F019FF606BCD /* VirtualTimeConverterType.swift */; }; + D6B4751CED01D53E4A1B6A571AAA2F83 /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7388BCBEE8E3D8292F5D6253EE8E2C5E /* HTTPMethod.swift */; }; + D709A58FF6A694878122F7D24B4A9913 /* Bag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D1F2097634F4C613AD8BAAD0128C338 /* Bag.swift */; }; + D8A4FE44301CF797B3E9655FA9F80FA6 /* _RXObjCRuntime.h in Headers */ = {isa = PBXBuildFile; fileRef = 0143446C5F00E24690553D7E4A4EF54C /* _RXObjCRuntime.h */; settings = {ATTRIBUTES = (Public, ); }; }; + DA34899BEF0668D76CBCE8C4CE47B97B /* RequestTaskMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32FFEA205095DE804BCFB4BA3E297506 /* RequestTaskMap.swift */; }; + DA736FAB25CE2D01EDB9B3196789B241 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD0CE05D5D076B1B5190EE5DF97FD54E /* Foundation.framework */; }; + DC17EB814ABCAF1ABEA2F1627752866B /* WithUnretained.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD97EB9B9E811F96C7484EB462830C06 /* WithUnretained.swift */; }; + DD724165EF3D8F209BD6EA6EEAA7EA0A /* RxSearchBarDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DBDD4E2905AB157F4C1B0DDC9AC1A2E /* RxSearchBarDelegateProxy.swift */; }; + DD902FE8D6824681C929D028655AE121 /* RequestInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10859DDF0B86C7AB30D77FC23A13C38 /* RequestInterceptor.swift */; }; + DDEF2B45CC47E733C9FCCD38F0BF6857 /* UIPickerView+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD8B024487048CCF8C23000257E0FDDA /* UIPickerView+Rx.swift */; }; + DE57D4F4A5577B90D3AE5CFEAB0386B9 /* SerialDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2B90B3B71B154BF22849D356E334730 /* SerialDisposable.swift */; }; + DF13840B7938888650B19F8D844DB422 /* SkipWhile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 453B4F0BA86A5AFEC030E0DB9B080DA8 /* SkipWhile.swift */; }; + DFD30F96D602E6476B57BB16FF1785D2 /* SharedSequence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3049D7F3DC3CF301B6D08F7BBCF9930B /* SharedSequence.swift */; }; + E352E97B987205D92E23CE464271278E /* SwiftSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0762669681B2AC7CE7998DDDB2D3F1F2 /* SwiftSupport.swift */; }; + E3C48387BE80334EA28DBB3F73ADA592 /* SubscribeOn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F1E1808D922AA079EF80B4EF1349FBF /* SubscribeOn.swift */; }; + E425FA08EAAE8E9961CC099844376D82 /* ScheduledDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E99C8AF3D55554B142A4F58C1CD027E4 /* ScheduledDisposable.swift */; }; + E4AB81BD6C225C98E39A8A81062485E8 /* Single.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C58CCC55F3E94E451DEEC457570FD6F /* Single.swift */; }; + E54654D504A42C24F284A68F87F7671D /* OperationQueue+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F6DD6B4E80ED9DDB1730AB62B8CDBC /* OperationQueue+Alamofire.swift */; }; + E6A1BF57511CE77AE62E000F61A5F48F /* _RXDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = A82B59C46A8891A0AF7A544DDCDBE7A4 /* _RXDelegateProxy.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E6F9EC2C837AEAD6CB9EAAB1EC05661F /* Zip+arity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6CEDE2E14A6455694E1E27F4AC1DA6B /* Zip+arity.swift */; }; + E9B4C89E7EB3B27D46AFCA452C3D426F /* MultipartUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65FA1855B83C5BE32DA991D72EEA3564 /* MultipartUpload.swift */; }; + EA0EA1B249889B5FCCB81A987B1B3692 /* RecursiveLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43A403DE21567DCAB3F49FC518B26B9 /* RecursiveLock.swift */; }; + EB276B66D2562F17B084C0D83B9D8F27 /* UISearchBar+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = C181BCCEF5CFDF4873D117F1CE6E1BA4 /* UISearchBar+Rx.swift */; }; + EB8FE24044E9093C48AADB3985FC7D43 /* LockOwnerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2103F4BAA235B84CE74EEACDD70D945E /* LockOwnerType.swift */; }; + EBF094241C1849BB99B08D995A12DE50 /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 329CA141F6D77E3069C111A94A5B2892 /* Queue.swift */; }; + EBF6254441C10CCC5F8C919AF9A8E8CF /* MainScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5D82CBB58DAD651E4DC89985DC41F8 /* MainScheduler.swift */; }; + EE80E1376D7F9E22682AE05EE3054388 /* UITabBar+Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510F8AF367E03012DF0695088BD61156 /* UITabBar+Rx.swift */; }; + EEC150B66BCCD6C80FDA7E4D1975166B /* DispatchQueue+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = E358CE05FC83CCB4181BCD48A6808920 /* DispatchQueue+Alamofire.swift */; }; + F059BB2BD4F7B156353739A55AEBE2A3 /* ObservableConvertibleType+Driver.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1021DE272385518E83073F8F688559B /* ObservableConvertibleType+Driver.swift */; }; + F0A8DBA0B324F3A63C8EF2DADB6FBF07 /* Rx.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0A7A8B1E275B8F3D59D65566FA08C2D /* Rx.swift */; }; + F0BF3B6C0494A86881130807FC9896FF /* Concat.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4607B3ED8CFA90C52AF18FFA2661128 /* Concat.swift */; }; + F0DC64268DD8A00793B71880D8A8124D /* SchedulerServices+Emulation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49A05763AF9D42793D8CEFE5AFD48977 /* SchedulerServices+Emulation.swift */; }; + F17A4CA4664CABB331D39FE902E06843 /* Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 378EBA5E2DCED169738F8B81FEC144CE /* Alamofire.swift */; }; + F1DA873728D70AB358E831F18AF284ED /* RxPickerViewDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D806B06479DC634E428071464C933F /* RxPickerViewDelegateProxy.swift */; }; + F219C2A0B49D73B93CEC939FEF1E7AB2 /* RxSearchControllerDelegateProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA094BCF75063D7C21A409A5551B01BE /* RxSearchControllerDelegateProxy.swift */; }; + F28CBBA286F282A892A5B564282BDDC9 /* Disposables.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F81D96A7B42E852FC0270A81AD5765 /* Disposables.swift */; }; + F387475B1EC3C098254F62698129B612 /* RxCocoaObjCRuntimeError+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1975EBAF55544BC70D2D790712F088CF /* RxCocoaObjCRuntimeError+Extensions.swift */; }; + F564D07AA19C49E882A68963914E55AA /* Infallible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D3FF377028729D3E8608459718B6E0 /* Infallible.swift */; }; + F5F07074DA7197374955965C99B49DE3 /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = E98E87EE662818FA7ED50231400C4D27 /* Window.swift */; }; + F6495BDDBBBB8B2B736175C1356622DF /* ObservableType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B44EDE211FB067BAA8C79521F169355 /* ObservableType.swift */; }; + F6E1B45243EF2546837B9099C53770E2 /* RxTableViewReactiveArrayDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF049EA98E5F9EE116DCE3833B01E3A8 /* RxTableViewReactiveArrayDataSource.swift */; }; + F6F9C34492E47A611E31D2D63F476F13 /* ItemEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26A34586BB25C239B0C93295410D6B7 /* ItemEvents.swift */; }; + F78AA3DD00AAD9DFD92BECF4CC1EBAC0 /* ObserverBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6A2B3CDA9EA6E76F57EDAB7349515F /* ObserverBase.swift */; }; + F89C351693522F78C6E85B6AAF7B76C4 /* RxCollectionViewDataSourceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 970FA5A266DB2924BBD2B982F74412EA /* RxCollectionViewDataSourceType.swift */; }; + F90BC71185AD63D583158C6F59992359 /* SubscriptionDisposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD27C6BF074BBDBCC0E702778BA185B3 /* SubscriptionDisposable.swift */; }; + F99CF4A8FDB51B0EB05DFD968E9EDE46 /* Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173EBD30721F23C387A602599E4316B8 /* Debug.swift */; }; + FA6537309E3B7A21A83E00774305275F /* Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 980E21F4EE794E4E1FF3E33D6882A259 /* Generate.swift */; }; + FCCB571EBE4AF1A4FBA44A16AEF28526 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0ABDFA66654E18EEE7E48DA5548533F /* Errors.swift */; }; + FDB6B50F3AF189818D8962D74E37D552 /* RxTableViewDataSourcePrefetchingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11AF7CE62967AC244F55DA9E1BB1811B /* RxTableViewDataSourcePrefetchingProxy.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 15D50F26F457497597AF3B7759D57DA7 /* PBXContainerItemProxy */ = { + 0147A0EC0EC18E201C8F6907A31C7CE2 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 52B60EC2A583F24ACBB69C113F5488B9; - remoteInfo = SwiftLint; + remoteGlobalIDString = 4622BFEF3DC16E8BD15EEFC30D4D0084; + remoteInfo = RxRelay; }; - 6E7213C929FE071F443403901BDF4ABB /* PBXContainerItemProxy */ = { + 8497A3C1D0917E4CBC7084CF881F0B7E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = EA9EA43B3B503823EE36C60D9C8A865F; remoteInfo = RxSwift; }; - 7D2B90F2E7CD87B00A9020B8BA08FBBA /* PBXContainerItemProxy */ = { + 95F383542701BD428AC157C1BD3EE71D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 4622BFEF3DC16E8BD15EEFC30D4D0084; - remoteInfo = RxRelay; + remoteGlobalIDString = 52B60EC2A583F24ACBB69C113F5488B9; + remoteInfo = SwiftLint; }; - A078FC00AD08CB78D3CEA95F1333F107 /* PBXContainerItemProxy */ = { + 98D1137759F9EF8EC531CB21569DB4BA /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 7AD0C6DCDC9CEC8A3C7C10C7FEE07BE6; - remoteInfo = RxCocoa; + remoteGlobalIDString = 4622BFEF3DC16E8BD15EEFC30D4D0084; + remoteInfo = RxRelay; }; - B1166BCF0F179451C7AED96AA3B51248 /* PBXContainerItemProxy */ = { + B61E5B448C60F66FAD91B55ECACE7930 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = EA9EA43B3B503823EE36C60D9C8A865F; remoteInfo = RxSwift; }; - E13393B041C7B09A9BAB70DF2B2E148A /* PBXContainerItemProxy */ = { + BA58DBBCD4416DD6F14156E1664F6154 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = EAAA1AD3A8A1B59AB91319EE40752C6D; + remoteInfo = Alamofire; + }; + CB63475E57D3D58955B7466F4B2CBAB1 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; remoteGlobalIDString = EA9EA43B3B503823EE36C60D9C8A865F; remoteInfo = RxSwift; }; - E53CE103361C949B39AA14128D342165 /* PBXContainerItemProxy */ = { + D64A74A50369D956BF1AB44709E4F388 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; proxyType = 1; - remoteGlobalIDString = 4622BFEF3DC16E8BD15EEFC30D4D0084; - remoteInfo = RxRelay; + remoteGlobalIDString = 7AD0C6DCDC9CEC8A3C7C10C7FEE07BE6; + remoteInfo = RxCocoa; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 00644668DE9E29E96EA7D4E75CC41005 /* NotificationCenter+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NotificationCenter+Rx.swift"; path = "RxCocoa/Foundation/NotificationCenter+Rx.swift"; sourceTree = ""; }; - 007E7595BA898B76D1D326F44A95B104 /* RxCollectionViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewReactiveArrayDataSource.swift; path = RxCocoa/iOS/DataSources/RxCollectionViewReactiveArrayDataSource.swift; sourceTree = ""; }; - 01AB5F3B630755C56EC18F68BF4C67EC /* _RXObjCRuntime.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXObjCRuntime.m; path = RxCocoa/Runtime/_RXObjCRuntime.m; sourceTree = ""; }; - 01B16DD2C82C26A727CDA0218AF2FB6D /* Cancelable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cancelable.swift; path = RxSwift/Cancelable.swift; sourceTree = ""; }; - 04344BD8BBAE6840F81D834C19D77C19 /* RetryWhen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RetryWhen.swift; path = RxSwift/Observables/RetryWhen.swift; sourceTree = ""; }; - 0517049528AB1D57EE93B9528EFC5077 /* DelaySubscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelaySubscription.swift; path = RxSwift/Observables/DelaySubscription.swift; sourceTree = ""; }; + 003BE23129F6FB245F50432D5F89E24B /* GroupBy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupBy.swift; path = RxSwift/Observables/GroupBy.swift; sourceTree = ""; }; + 004BA208237B4E16EA699ACADC85AFE0 /* RxWKNavigationDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxWKNavigationDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxWKNavigationDelegateProxy.swift; sourceTree = ""; }; + 011724A1A671D7E12ABD37BC873AE4BA /* WKWebView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "WKWebView+Rx.swift"; path = "RxCocoa/iOS/WKWebView+Rx.swift"; sourceTree = ""; }; + 011C15D0AD92913A044FD01816592922 /* SharedSequence+Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SharedSequence+Operators.swift"; path = "RxCocoa/Traits/SharedSequence/SharedSequence+Operators.swift"; sourceTree = ""; }; + 012453260A0F0691E70C3944FFAF048C /* NSSlider+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSSlider+Rx.swift"; path = "RxCocoa/macOS/NSSlider+Rx.swift"; sourceTree = ""; }; + 0143446C5F00E24690553D7E4A4EF54C /* _RXObjCRuntime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXObjCRuntime.h; path = RxCocoa/Runtime/include/_RXObjCRuntime.h; sourceTree = ""; }; + 01D3FF377028729D3E8608459718B6E0 /* Infallible.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Infallible.swift; path = RxSwift/Traits/Infallible/Infallible.swift; sourceTree = ""; }; + 0367676A099A476FEA0C5CB232616A22 /* Observable+Bind.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Observable+Bind.swift"; path = "RxRelay/Observable+Bind.swift"; sourceTree = ""; }; + 03AD707277DF16D02FC728818FCA494F /* InfiniteSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfiniteSequence.swift; path = Platform/DataStructures/InfiniteSequence.swift; sourceTree = ""; }; + 03B62EC386D75F6A3C259E3A603A4CF8 /* Concurrency.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Concurrency.swift; path = Source/Concurrency.swift; sourceTree = ""; }; + 0409B4163021C318D05F2A0F97350868 /* RxRelay.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxRelay.debug.xcconfig; sourceTree = ""; }; + 0424BF5445C2DE265C48275A088BD3C0 /* DelaySubscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelaySubscription.swift; path = RxSwift/Observables/DelaySubscription.swift; sourceTree = ""; }; + 0574C75A44746F41A2D4CE995EFFC811 /* Alamofire-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Alamofire-Info.plist"; sourceTree = ""; }; + 057F21FAE790F4DD0A18A93296D0A71E /* _RX.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RX.h; path = RxCocoa/Runtime/include/_RX.h; sourceTree = ""; }; + 0640980150BB98AE63D6937157CEB1C8 /* Do.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Do.swift; path = RxSwift/Observables/Do.swift; sourceTree = ""; }; + 064F1CAB9993B8292FFC49F391E694E6 /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = RxSwift/Observables/Error.swift; sourceTree = ""; }; 067C5060D387C9D14BFF5607B37FDF52 /* Pods-Instagram-Clone-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Instagram-Clone-Info.plist"; sourceTree = ""; }; - 06AA9C625F3E30335B298A5366E2682C /* Sink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sink.swift; path = RxSwift/Observables/Sink.swift; sourceTree = ""; }; - 06BE21461C247B540A28540AD7B0C5F0 /* UIActivityIndicatorView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIActivityIndicatorView+Rx.swift"; path = "RxCocoa/iOS/UIActivityIndicatorView+Rx.swift"; sourceTree = ""; }; - 0775DFAAB9181064CDE9A004E96E7D3C /* UISlider+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISlider+Rx.swift"; path = "RxCocoa/iOS/UISlider+Rx.swift"; sourceTree = ""; }; - 07EE5CA97A79FC56E99B357F91998429 /* RxRelay.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxRelay.modulemap; sourceTree = ""; }; - 089965FFF10BAC759D5721DA13057A92 /* Repeat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Repeat.swift; path = RxSwift/Observables/Repeat.swift; sourceTree = ""; }; - 08B063219062CCBA4FC87611947A024D /* CompactMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompactMap.swift; path = RxSwift/Observables/CompactMap.swift; sourceTree = ""; }; - 09783CE839BFEBF2D75D0FDCD24233B5 /* Platform.Linux.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Linux.swift; path = Platform/Platform.Linux.swift; sourceTree = ""; }; - 0B92717286BC70F18FCB3A9C3C72A5C6 /* RxCollectionViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDelegateProxy.swift; sourceTree = ""; }; - 0C7C50211D78C2371DED7C720B94CFEF /* Window.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Window.swift; path = RxSwift/Observables/Window.swift; sourceTree = ""; }; - 0D63B0B75043E16A5215A4ECA19471EC /* Maybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Maybe.swift; path = RxSwift/Traits/PrimitiveSequence/Maybe.swift; sourceTree = ""; }; - 0D864E28EC1869A5B35ECEDD2E5D8C68 /* PriorityQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = Platform/DataStructures/PriorityQueue.swift; sourceTree = ""; }; - 0DC79611286237FB7BE7F29EDEB2421B /* RxSearchBarDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxSearchBarDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxSearchBarDelegateProxy.swift; sourceTree = ""; }; - 0DFF0ABC6B463C32F017539E758D6582 /* UIGestureRecognizer+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIGestureRecognizer+Rx.swift"; path = "RxCocoa/iOS/UIGestureRecognizer+Rx.swift"; sourceTree = ""; }; - 0EF1EEEFAE14249E6C2D2565A94EEA04 /* Using.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Using.swift; path = RxSwift/Observables/Using.swift; sourceTree = ""; }; - 108B75EB704DE92E5D545B3BC0B813CD /* UIBarButtonItem+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIBarButtonItem+Rx.swift"; path = "RxCocoa/iOS/UIBarButtonItem+Rx.swift"; sourceTree = ""; }; - 149172E51A3A87DAF5B5A38EF9199C6D /* SubscribeOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscribeOn.swift; path = RxSwift/Observables/SubscribeOn.swift; sourceTree = ""; }; - 14EBA27517C50FBCE1EA2A7A2A459843 /* RxSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxSwift.modulemap; sourceTree = ""; }; - 15299F3579C722B10ACF13813B53ABCA /* Timer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timer.swift; path = RxSwift/Observables/Timer.swift; sourceTree = ""; }; - 1640FC349F21362CD2F1E8C375FEB710 /* InfiniteSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfiniteSequence.swift; path = Platform/DataStructures/InfiniteSequence.swift; sourceTree = ""; }; - 1699725A75E793AF47AFA08A03CAAFA5 /* KVORepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KVORepresentable.swift; path = RxCocoa/Foundation/KVORepresentable.swift; sourceTree = ""; }; - 17385DE72069A424DE83D6B4072A92A5 /* UIScrollView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIScrollView+Rx.swift"; path = "RxCocoa/iOS/UIScrollView+Rx.swift"; sourceTree = ""; }; - 18B3621E91765CDCDD2F0E491A5418EE /* VirtualTimeScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeScheduler.swift; path = RxSwift/Schedulers/VirtualTimeScheduler.swift; sourceTree = ""; }; - 193BF64313DB29C3FCF62CB0CF3133BD /* Platform.Darwin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Darwin.swift; path = Platform/Platform.Darwin.swift; sourceTree = ""; }; - 193EB48EF2C7E8AFF355077AEE6C05D3 /* RxTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTarget.swift; path = RxCocoa/Common/RxTarget.swift; sourceTree = ""; }; - 1BCC3DE64EB6BD619B9D9CF5F8E5F1F9 /* Timeout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timeout.swift; path = RxSwift/Observables/Timeout.swift; sourceTree = ""; }; - 1C55F92F39ECE075EE04F1D61EFC0326 /* HistoricalScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalScheduler.swift; path = RxSwift/Schedulers/HistoricalScheduler.swift; sourceTree = ""; }; - 1C61DA0F4B8F6066A14AEF98A1D31D00 /* RxCocoa-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxCocoa-umbrella.h"; sourceTree = ""; }; - 1D7D582FFA9DDD192BBDF4FABA8D16D7 /* RxSwift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxSwift-Info.plist"; sourceTree = ""; }; - 1EE9FE35EE4E7109EA34CC2443F5C817 /* DelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelegateProxy.swift; path = RxCocoa/Common/DelegateProxy.swift; sourceTree = ""; }; - 21ACAD4D869127D49821CD63EEE486D1 /* NSTextField+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextField+Rx.swift"; path = "RxCocoa/macOS/NSTextField+Rx.swift"; sourceTree = ""; }; - 2235370476372BE73664E895A421D4FF /* RxPickerViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxPickerViewDataSourceType.swift; sourceTree = ""; }; - 22BD2B18828CB266956CE4D931265F42 /* SectionedViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SectionedViewDataSourceType.swift; path = RxCocoa/Common/SectionedViewDataSourceType.swift; sourceTree = ""; }; - 2385E1134EA158765A41A546E3AE33BC /* Zip+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+Collection.swift"; path = "RxSwift/Observables/Zip+Collection.swift"; sourceTree = ""; }; - 23CF8C2915AF525BE23908E7FE1610A5 /* UIPickerView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIPickerView+Rx.swift"; path = "RxCocoa/iOS/UIPickerView+Rx.swift"; sourceTree = ""; }; - 24701C2CDA783D537E98D65A2919ADBB /* RxRelay.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxRelay.debug.xcconfig; sourceTree = ""; }; - 253971F450F05D5006DDD0D919450D87 /* SubscriptionDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscriptionDisposable.swift; path = RxSwift/Disposables/SubscriptionDisposable.swift; sourceTree = ""; }; - 26410040C396641DC2A2ABA618935E26 /* DistinctUntilChanged.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DistinctUntilChanged.swift; path = RxSwift/Observables/DistinctUntilChanged.swift; sourceTree = ""; }; - 265DFB94C2AE7AC0DC8CB4C276047CB6 /* PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PrimitiveSequence.swift; path = RxSwift/Traits/PrimitiveSequence/PrimitiveSequence.swift; sourceTree = ""; }; - 27564198C961BEDCB7B0B8D2E04EE4B2 /* RxTableViewDataSourcePrefetchingProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourcePrefetchingProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDataSourcePrefetchingProxy.swift; sourceTree = ""; }; - 285F374E9AFE8CE7A829816006FDEF7B /* Range.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Range.swift; path = RxSwift/Observables/Range.swift; sourceTree = ""; }; - 28A63C60790F5C7200738F8A762FE5B9 /* WithLatestFrom.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WithLatestFrom.swift; path = RxSwift/Observables/WithLatestFrom.swift; sourceTree = ""; }; - 299E7425E04B095442F4A077219619DB /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Platform/DataStructures/Bag.swift; sourceTree = ""; }; - 2B51F3BF99D9237CADBEED71883FFEA2 /* Driver+Subscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Driver+Subscription.swift"; path = "RxCocoa/Traits/Driver/Driver+Subscription.swift"; sourceTree = ""; }; - 2B91A7A9E5D728BE812EADFF1C66A76E /* PriorityQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = Platform/DataStructures/PriorityQueue.swift; sourceTree = ""; }; - 2BC86CE63EC0703205D3A01D0D570F08 /* Just.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Just.swift; path = RxSwift/Observables/Just.swift; sourceTree = ""; }; - 2CC9D60AB695554951311124842EEABC /* TextInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TextInput.swift; path = RxCocoa/Common/TextInput.swift; sourceTree = ""; }; - 2CE52486EB2B3A9A3A429A00A5754CA9 /* Event.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Event.swift; path = RxSwift/Event.swift; sourceTree = ""; }; - 2D9539B4F49FEE65309ABE756D3F4786 /* Completable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Completable.swift; path = RxSwift/Traits/PrimitiveSequence/Completable.swift; sourceTree = ""; }; - 2DE36FB3974AF4A9D156AC0FAEFB182C /* RxCollectionViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxCollectionViewDataSourceType.swift; sourceTree = ""; }; - 2E04188FA34CE390796D91FF5E2B8886 /* SingleAsync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAsync.swift; path = RxSwift/Observables/SingleAsync.swift; sourceTree = ""; }; - 2E1283226017D88FCEDBE4D65F0E2E0B /* RxTableViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewReactiveArrayDataSource.swift; path = RxCocoa/iOS/DataSources/RxTableViewReactiveArrayDataSource.swift; sourceTree = ""; }; - 2F114313913428BF0B3DF63F4A9D3128 /* Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Rx.swift; path = RxSwift/Rx.swift; sourceTree = ""; }; - 32B14FB3822E731DB6D717BCE0D19DEE /* SchedulerServices+Emulation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SchedulerServices+Emulation.swift"; path = "RxSwift/Schedulers/SchedulerServices+Emulation.swift"; sourceTree = ""; }; - 338E26527677E48EDF3516E1ADA885D0 /* Take.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Take.swift; path = RxSwift/Observables/Take.swift; sourceTree = ""; }; - 3419D41B8498B933438FAFDA15054252 /* RxSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-prefix.pch"; sourceTree = ""; }; - 3532C567B8EB7BAB306DDA6CA277B84D /* CombineLatest+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+arity.swift"; path = "RxSwift/Observables/CombineLatest+arity.swift"; sourceTree = ""; }; - 359C8B4E3F1950C1B077B313A05E98AC /* KVORepresentable+CoreGraphics.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "KVORepresentable+CoreGraphics.swift"; path = "RxCocoa/Foundation/KVORepresentable+CoreGraphics.swift"; sourceTree = ""; }; - 369E994557E0AC577044CE1CB58008D8 /* NSButton+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSButton+Rx.swift"; path = "RxCocoa/macOS/NSButton+Rx.swift"; sourceTree = ""; }; - 383C2AC03F6C6BD740AEDB5F72435FBB /* Concat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Concat.swift; path = RxSwift/Observables/Concat.swift; sourceTree = ""; }; - 3B6EF5FB2BA8D6F9CA45221D11FCBBA5 /* ControlProperty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlProperty.swift; path = RxCocoa/Traits/ControlProperty.swift; sourceTree = ""; }; - 3BE14BF9AF5DB36145DD2FF859822332 /* ScheduledItemType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItemType.swift; path = RxSwift/Schedulers/Internal/ScheduledItemType.swift; sourceTree = ""; }; - 3C8A1A3FEB0F250D55F66A3C867BBDB9 /* RxCocoa-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxCocoa-Info.plist"; sourceTree = ""; }; - 3D10FE0979AA30BC837E8945BE181EAC /* ToArray.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ToArray.swift; path = RxSwift/Observables/ToArray.swift; sourceTree = ""; }; - 3E452B621A51772D2378F31494E12D32 /* CombineLatest.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombineLatest.swift; path = RxSwift/Observables/CombineLatest.swift; sourceTree = ""; }; - 3E69A66DD64CE026C3088FCE23AC5A8D /* Sample.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sample.swift; path = RxSwift/Observables/Sample.swift; sourceTree = ""; }; - 3F03494C7F9242E59237EC6E7B3A8D6F /* _RX.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RX.m; path = RxCocoa/Runtime/_RX.m; sourceTree = ""; }; - 3F03CA510076C25FCD452E992F2EF3CA /* RxCocoa.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RxCocoa.h; path = RxCocoa/RxCocoa.h; sourceTree = ""; }; - 3FB3DECF9FA15E273D3F48AA2E9AEAB7 /* ConnectableObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConnectableObservableType.swift; path = RxSwift/ConnectableObservableType.swift; sourceTree = ""; }; - 404475EF1E226D1D3703A1AA7D0F355F /* ElementAt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ElementAt.swift; path = RxSwift/Observables/ElementAt.swift; sourceTree = ""; }; - 40661C9CD5EA78C14FF62DF719B11B18 /* SwiftSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftSupport.swift; path = RxSwift/SwiftSupport/SwiftSupport.swift; sourceTree = ""; }; - 42E8C86A17D8344F4AFE300FDA80AB49 /* RxCocoa.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxCocoa.debug.xcconfig; sourceTree = ""; }; - 431ED4903DBAE9C89C9C0473B2E0E298 /* Zip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Zip.swift; path = RxSwift/Observables/Zip.swift; sourceTree = ""; }; - 44C06230C881B6028853B66557DBFEE6 /* RxCocoa-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxCocoa-dummy.m"; sourceTree = ""; }; - 4670F49FCE04BE2C9B9127D7C02F25CB /* SingleAssignmentDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAssignmentDisposable.swift; path = RxSwift/Disposables/SingleAssignmentDisposable.swift; sourceTree = ""; }; - 47C9C5568753DC4ABA0764707F468FD3 /* Buffer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Buffer.swift; path = RxSwift/Observables/Buffer.swift; sourceTree = ""; }; + 0755115E5EB323278C37AC66CAAE2B1A /* UIControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIControl+Rx.swift"; path = "RxCocoa/iOS/UIControl+Rx.swift"; sourceTree = ""; }; + 0762669681B2AC7CE7998DDDB2D3F1F2 /* SwiftSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwiftSupport.swift; path = RxSwift/SwiftSupport/SwiftSupport.swift; sourceTree = ""; }; + 07BFF01DC46CE2B8775DB7C2333A4181 /* Cancelable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cancelable.swift; path = RxSwift/Cancelable.swift; sourceTree = ""; }; + 0804998A043E63BCF0404A778DEE29D8 /* UIButton+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIButton+Rx.swift"; path = "RxCocoa/iOS/UIButton+Rx.swift"; sourceTree = ""; }; + 09E5E4F2BCD53E7623C2C55EA38378DD /* VirtualTimeScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeScheduler.swift; path = RxSwift/Schedulers/VirtualTimeScheduler.swift; sourceTree = ""; }; + 0AD7897AC94CD3CD139D7249BCBA09AA /* Alamofire.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Alamofire.release.xcconfig; sourceTree = ""; }; + 0B286A5673B1B7539EAE7FB20F57F746 /* RxCollectionViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDelegateProxy.swift; sourceTree = ""; }; + 0BC849CCA664038F11F4F805A1D72D7A /* RxSwift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-prefix.pch"; sourceTree = ""; }; + 0D1078A15FDA40825DA0C34D1DCD56C0 /* KVORepresentable+Swift.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "KVORepresentable+Swift.swift"; path = "RxCocoa/Foundation/KVORepresentable+Swift.swift"; sourceTree = ""; }; + 0DFAFE2B7445F5066808C50D6442C72C /* AlamofireExtended.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AlamofireExtended.swift; path = Source/AlamofireExtended.swift; sourceTree = ""; }; + 0E3AEF057D82E1811AD90C4DE2267A79 /* Driver+Subscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Driver+Subscription.swift"; path = "RxCocoa/Traits/Driver/Driver+Subscription.swift"; sourceTree = ""; }; + 0EB397BBE2053179721ACC128AC15CEA /* ObservableConvertibleType+Infallible.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+Infallible.swift"; path = "RxSwift/Traits/Infallible/ObservableConvertibleType+Infallible.swift"; sourceTree = ""; }; + 0F1BCE55561F2EDA941C3A3A1284DC55 /* NetworkReachabilityManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NetworkReachabilityManager.swift; path = Source/NetworkReachabilityManager.swift; sourceTree = ""; }; + 0F365E68BF9F85C934803EEE843C7507 /* _RXObjCRuntime.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXObjCRuntime.m; path = RxCocoa/Runtime/_RXObjCRuntime.m; sourceTree = ""; }; + 103354D756EEF3F7108DEC03A6165EEC /* SubjectType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubjectType.swift; path = RxSwift/Subjects/SubjectType.swift; sourceTree = ""; }; + 10683973D347C94E5EAFC16D41AFD67E /* Throttle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Throttle.swift; path = RxSwift/Observables/Throttle.swift; sourceTree = ""; }; + 112241935E9BE9CFD251FB234B0FB839 /* Event.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Event.swift; path = RxSwift/Event.swift; sourceTree = ""; }; + 11AF7CE62967AC244F55DA9E1BB1811B /* RxTableViewDataSourcePrefetchingProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourcePrefetchingProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDataSourcePrefetchingProxy.swift; sourceTree = ""; }; + 11D4AFEAB2754F664EEDD11730507922 /* ObservableConvertibleType+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+Signal.swift"; path = "RxCocoa/Traits/Signal/ObservableConvertibleType+Signal.swift"; sourceTree = ""; }; + 12427AF8DF82101B9D78DAB0E6F28AAA /* SectionedViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SectionedViewDataSourceType.swift; path = RxCocoa/Common/SectionedViewDataSourceType.swift; sourceTree = ""; }; + 132F36A02348DB3BCDBDACFEF9CB787A /* ConnectableObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConnectableObservableType.swift; path = RxSwift/ConnectableObservableType.swift; sourceTree = ""; }; + 171C5F87CB9880D7A87F28226F3A2966 /* RxTextViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTextViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTextViewDelegateProxy.swift; sourceTree = ""; }; + 173EBD30721F23C387A602599E4316B8 /* Debug.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debug.swift; path = RxSwift/Observables/Debug.swift; sourceTree = ""; }; + 17878B482853B987E43D970E0F91E0B5 /* Maybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Maybe.swift; path = RxSwift/Traits/PrimitiveSequence/Maybe.swift; sourceTree = ""; }; + 17E9145798CDAECA8E6048A90E9D4748 /* NSObject+Rx+KVORepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx+KVORepresentable.swift"; path = "RxCocoa/Foundation/NSObject+Rx+KVORepresentable.swift"; sourceTree = ""; }; + 1975EBAF55544BC70D2D790712F088CF /* RxCocoaObjCRuntimeError+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "RxCocoaObjCRuntimeError+Extensions.swift"; path = "RxCocoa/Common/RxCocoaObjCRuntimeError+Extensions.swift"; sourceTree = ""; }; + 1AE2C2EADA7F5DB06B8F3226F9EA5B97 /* RxCocoa-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxCocoa-prefix.pch"; sourceTree = ""; }; + 1B20B9F6EB6E0D8B0DCE2E0A406D8986 /* ParameterEncoding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParameterEncoding.swift; path = Source/ParameterEncoding.swift; sourceTree = ""; }; + 1CA391017BD2A3678044F22FCDCC8E74 /* Completable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Completable.swift; path = RxSwift/Traits/PrimitiveSequence/Completable.swift; sourceTree = ""; }; + 1CE9464205009D39C62EE5E3B85E6260 /* AFError.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AFError.swift; path = Source/AFError.swift; sourceTree = ""; }; + 1DAA98713A8129DA8D7F67CFEB63F07A /* Reactive.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reactive.swift; path = RxSwift/Reactive.swift; sourceTree = ""; }; + 1EE8D25372CE963CE58F7C2F4FB187CF /* NotificationCenter+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NotificationCenter+Rx.swift"; path = "RxCocoa/Foundation/NotificationCenter+Rx.swift"; sourceTree = ""; }; + 1F36285EAC13EEE1ECCF3F9D7FD36466 /* GroupedObservable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupedObservable.swift; path = RxSwift/GroupedObservable.swift; sourceTree = ""; }; + 20BC4B195BA7EB8AF77DA60381FCCD43 /* Timeout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timeout.swift; path = RxSwift/Observables/Timeout.swift; sourceTree = ""; }; + 20C5AA8122AA25F6AE43D02B1AB787B4 /* Validation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Validation.swift; path = Source/Validation.swift; sourceTree = ""; }; + 2103F4BAA235B84CE74EEACDD70D945E /* LockOwnerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LockOwnerType.swift; path = RxSwift/Concurrency/LockOwnerType.swift; sourceTree = ""; }; + 2187E0B6C891F3F1767EE5994A0A04F1 /* Optional.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Optional.swift; path = RxSwift/Observables/Optional.swift; sourceTree = ""; }; + 22AAD42AC2A848D8F7BFEFB4DC3A8879 /* Alamofire-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Alamofire-dummy.m"; sourceTree = ""; }; + 237C88B64E2FC4D82877BD5916785674 /* DelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelegateProxy.swift; path = RxCocoa/Common/DelegateProxy.swift; sourceTree = ""; }; + 244E51A33CB5B29ADFE25976FDA0E00E /* Platform.Darwin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Darwin.swift; path = Platform/Platform.Darwin.swift; sourceTree = ""; }; + 252782DAFEE92AF927AF401D81DC4756 /* RxCocoaRuntime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RxCocoaRuntime.h; path = RxCocoa/Runtime/include/RxCocoaRuntime.h; sourceTree = ""; }; + 256B92342A5164F30F9289C7D50E5A6C /* RxPickerViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxPickerViewDataSourceProxy.swift; sourceTree = ""; }; + 257DE2F860194DE5AA9E2B2782DF8793 /* ImmediateSchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImmediateSchedulerType.swift; path = RxSwift/ImmediateSchedulerType.swift; sourceTree = ""; }; + 267DB70A0C2AB28FC178E80A0718B8AB /* PriorityQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = Platform/DataStructures/PriorityQueue.swift; sourceTree = ""; }; + 26C3823CD02898688DB8C4C27D6F1450 /* UITextField+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITextField+Rx.swift"; path = "RxCocoa/iOS/UITextField+Rx.swift"; sourceTree = ""; }; + 2934C5C2C05618A3D6A55FE1795714E0 /* Using.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Using.swift; path = RxSwift/Observables/Using.swift; sourceTree = ""; }; + 29E0682772F7E3BF82479D100F042D2A /* SwiftLint.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftLint.debug.xcconfig; sourceTree = ""; }; + 2A06AA26688719BE78A832A68E8139C0 /* SwiftLint.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftLint.release.xcconfig; sourceTree = ""; }; + 2B74DB1EE448E983BD57207719A6ADAE /* CombineLatest+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+Collection.swift"; path = "RxSwift/Observables/CombineLatest+Collection.swift"; sourceTree = ""; }; + 2CCCF0F617B295E0168704E10183E07A /* RxNavigationControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxNavigationControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxNavigationControllerDelegateProxy.swift; sourceTree = ""; }; + 2D1F2097634F4C613AD8BAAD0128C338 /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Platform/DataStructures/Bag.swift; sourceTree = ""; }; + 2EB486C2DC92FC85AE2811D80085646E /* StringEncoding+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "StringEncoding+Alamofire.swift"; path = "Source/StringEncoding+Alamofire.swift"; sourceTree = ""; }; + 3049D7F3DC3CF301B6D08F7BBCF9930B /* SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SharedSequence.swift; path = RxCocoa/Traits/SharedSequence/SharedSequence.swift; sourceTree = ""; }; + 3126D57CF6D0BC79B9BD8D382FDFF41F /* Session.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Session.swift; path = Source/Session.swift; sourceTree = ""; }; + 31FC37E7C3FDBAA92A3B8F8C6E840F31 /* NSControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSControl+Rx.swift"; path = "RxCocoa/macOS/NSControl+Rx.swift"; sourceTree = ""; }; + 329CA141F6D77E3069C111A94A5B2892 /* Queue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = Platform/DataStructures/Queue.swift; sourceTree = ""; }; + 32BA8073424D0DF7ECECDDB2EF816A68 /* URLSessionConfiguration+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLSessionConfiguration+Alamofire.swift"; path = "Source/URLSessionConfiguration+Alamofire.swift"; sourceTree = ""; }; + 32FFEA205095DE804BCFB4BA3E297506 /* RequestTaskMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RequestTaskMap.swift; path = Source/RequestTaskMap.swift; sourceTree = ""; }; + 33B20AE498859D4D4AF71FD9B168684F /* ToArray.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ToArray.swift; path = RxSwift/Observables/ToArray.swift; sourceTree = ""; }; + 35BF645AE8BDB43F5F91AA91349F1B63 /* SwitchIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwitchIfEmpty.swift; path = RxSwift/Observables/SwitchIfEmpty.swift; sourceTree = ""; }; + 363A4B179A004E5C46D5AEDEEFD28431 /* RxSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxSwift.debug.xcconfig; sourceTree = ""; }; + 366AB29585827B22DA277DCC64C6210D /* RxTabBarControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTabBarControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTabBarControllerDelegateProxy.swift; sourceTree = ""; }; + 3673AC5B3124EC7A5ADE41E8D4A32E38 /* Protected.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Protected.swift; path = Source/Protected.swift; sourceTree = ""; }; + 378EBA5E2DCED169738F8B81FEC144CE /* Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Alamofire.swift; path = Source/Alamofire.swift; sourceTree = ""; }; + 39BFF1F4303B0AE6E2D295DD49C76DC2 /* BooleanDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BooleanDisposable.swift; path = RxSwift/Disposables/BooleanDisposable.swift; sourceTree = ""; }; + 3A528F662FE12267714BB9BD1308F560 /* DefaultIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DefaultIfEmpty.swift; path = RxSwift/Observables/DefaultIfEmpty.swift; sourceTree = ""; }; + 3B5D82CBB58DAD651E4DC89985DC41F8 /* MainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MainScheduler.swift; path = RxSwift/Schedulers/MainScheduler.swift; sourceTree = ""; }; + 3B86CA8FB56D594D41CF699D266A6FBE /* AsyncLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncLock.swift; path = RxSwift/Concurrency/AsyncLock.swift; sourceTree = ""; }; + 3C193EEDF6B5EBAB9D21CA69760F3160 /* UIActivityIndicatorView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIActivityIndicatorView+Rx.swift"; path = "RxCocoa/iOS/UIActivityIndicatorView+Rx.swift"; sourceTree = ""; }; + 3C890F215AF0CB31979E34F7A9F3B85C /* Skip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Skip.swift; path = RxSwift/Observables/Skip.swift; sourceTree = ""; }; + 3D762331D58A21757B046C90540486FC /* Scan.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Scan.swift; path = RxSwift/Observables/Scan.swift; sourceTree = ""; }; + 4104B378EA3EBFE66129D192B22A2627 /* Lock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Lock.swift; path = RxSwift/Concurrency/Lock.swift; sourceTree = ""; }; + 41A8370357890336F08FB952BD79117F /* RxPickerViewAdapter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewAdapter.swift; path = RxCocoa/iOS/DataSources/RxPickerViewAdapter.swift; sourceTree = ""; }; + 41F27E716EA312BE508938A789401C98 /* AnonymousObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousObserver.swift; path = RxSwift/Observers/AnonymousObserver.swift; sourceTree = ""; }; + 425614E9FB485B7AFD1395F3890AEB4F /* Platform.Linux.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Linux.swift; path = Platform/Platform.Linux.swift; sourceTree = ""; }; + 431CE5CA440EADE478463371D8940E0F /* Zip+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+Collection.swift"; path = "RxSwift/Observables/Zip+Collection.swift"; sourceTree = ""; }; + 43CF235C9231F1361CBDDE0EC92FA624 /* Amb.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Amb.swift; path = RxSwift/Observables/Amb.swift; sourceTree = ""; }; + 44621BE174840A776DA54345ED8C22F6 /* Notifications.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Notifications.swift; path = Source/Notifications.swift; sourceTree = ""; }; + 44B8E99A079E190217E678B7AAFC79DA /* UIScrollView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIScrollView+Rx.swift"; path = "RxCocoa/iOS/UIScrollView+Rx.swift"; sourceTree = ""; }; + 453B4F0BA86A5AFEC030E0DB9B080DA8 /* SkipWhile.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipWhile.swift; path = RxSwift/Observables/SkipWhile.swift; sourceTree = ""; }; + 46AE8C1E9DACE1C8DDBD6126304A9EE5 /* CurrentThreadScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CurrentThreadScheduler.swift; path = RxSwift/Schedulers/CurrentThreadScheduler.swift; sourceTree = ""; }; + 46E3B0C82A8F4E4AF7951C604C8D41F8 /* RxRelay-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxRelay-dummy.m"; sourceTree = ""; }; + 470212E66C74D5757E37A837E2B1F0FD /* RxScrollViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxScrollViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxScrollViewDelegateProxy.swift; sourceTree = ""; }; + 482E10370BAB6DE666A35873DE1DA9AF /* StartWith.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StartWith.swift; path = RxSwift/Observables/StartWith.swift; sourceTree = ""; }; 4894F90605FBEA7B041ED3C5E033C0EC /* Pods-Instagram-Clone-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Instagram-Clone-dummy.m"; sourceTree = ""; }; - 499F02441FA51A23F940FA3843DF9A39 /* ObservableConvertibleType+SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+SharedSequence.swift"; path = "RxCocoa/Traits/SharedSequence/ObservableConvertibleType+SharedSequence.swift"; sourceTree = ""; }; - 4A8BA0F62E7457838B8C4E134C2A48FF /* UITabBarController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITabBarController+Rx.swift"; path = "RxCocoa/iOS/UITabBarController+Rx.swift"; sourceTree = ""; }; - 4AE21CFC451474A9312ADDDF69FDB6D4 /* RxPickerViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxPickerViewDelegateProxy.swift; sourceTree = ""; }; - 4BAE0BC077E8C62320097689E54D211B /* _RXDelegateProxy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXDelegateProxy.m; path = RxCocoa/Runtime/_RXDelegateProxy.m; sourceTree = ""; }; - 4C4B4A36966A9C04C9538B5C5E2150C6 /* RxCocoaRuntime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RxCocoaRuntime.h; path = RxCocoa/Runtime/include/RxCocoaRuntime.h; sourceTree = ""; }; - 4CE9F2DE870FB9EA5E6080F76C2DA110 /* ItemEvents.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ItemEvents.swift; path = RxCocoa/iOS/Events/ItemEvents.swift; sourceTree = ""; }; - 4D6F74828D23AA06327E94D4B11F0483 /* VirtualTimeConverterType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeConverterType.swift; path = RxSwift/Schedulers/VirtualTimeConverterType.swift; sourceTree = ""; }; - 4D7E732DE2B0F4DDEEB2A48C3793EA57 /* RxCollectionViewDataSourcePrefetchingProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourcePrefetchingProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDataSourcePrefetchingProxy.swift; sourceTree = ""; }; - 4F297B2AB79CC5002645FF512CDC17EB /* UIApplication+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIApplication+Rx.swift"; path = "RxCocoa/iOS/UIApplication+Rx.swift"; sourceTree = ""; }; - 5034BAB8BD865EB2CEB711500C270EB8 /* SubjectType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubjectType.swift; path = RxSwift/Subjects/SubjectType.swift; sourceTree = ""; }; - 508A20901B2C356FEAAF7D14031050F6 /* ScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItem.swift; path = RxSwift/Schedulers/Internal/ScheduledItem.swift; sourceTree = ""; }; - 5232F0716373C6707AA30C634546FCAE /* RefCountDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RefCountDisposable.swift; path = RxSwift/Disposables/RefCountDisposable.swift; sourceTree = ""; }; - 523F251A7D75246E6AEF64CEE3209F7A /* TakeLast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeLast.swift; path = RxSwift/Observables/TakeLast.swift; sourceTree = ""; }; - 52D7FC2FBFC96464543FC2D5284CC469 /* Error.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Error.swift; path = RxSwift/Observables/Error.swift; sourceTree = ""; }; - 52E585039525D24078FD09A43C1FB4E2 /* AsyncLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncLock.swift; path = RxSwift/Concurrency/AsyncLock.swift; sourceTree = ""; }; - 544B2D6150A77A085C21CB5926471FE1 /* Delay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Delay.swift; path = RxSwift/Observables/Delay.swift; sourceTree = ""; }; - 546E57E00BC246C6761986A013FB0DCA /* Deferred.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deferred.swift; path = RxSwift/Observables/Deferred.swift; sourceTree = ""; }; - 55502E9CDD82DB3C088023E52EF29CAF /* Create.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Create.swift; path = RxSwift/Observables/Create.swift; sourceTree = ""; }; - 5574A45114B7AF48A6DE11C97987BFB6 /* AtomicInt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AtomicInt.swift; path = Platform/AtomicInt.swift; sourceTree = ""; }; - 562BCC9B350F163DACF15AA79D23DC08 /* Infallible+Bind.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Infallible+Bind.swift"; path = "RxCocoa/Common/Infallible+Bind.swift"; sourceTree = ""; }; - 570D56F0F47A06EF81090D3C20ACC26C /* Binder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Binder.swift; path = RxSwift/Binder.swift; sourceTree = ""; }; - 59CF1146BFFC0D96B3CC4F517DE8E4E1 /* UINavigationController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UINavigationController+Rx.swift"; path = "RxCocoa/iOS/UINavigationController+Rx.swift"; sourceTree = ""; }; + 49A05763AF9D42793D8CEFE5AFD48977 /* SchedulerServices+Emulation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SchedulerServices+Emulation.swift"; path = "RxSwift/Schedulers/SchedulerServices+Emulation.swift"; sourceTree = ""; }; + 4A218B60A6F3B33C317DFF65DD678205 /* RxTableViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDataSourceProxy.swift; sourceTree = ""; }; + 4B8D740B9CD39CEBBE02FD72043BA317 /* Delay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Delay.swift; path = RxSwift/Observables/Delay.swift; sourceTree = ""; }; + 4B9AA9F85FB7028720BC48147A7340E8 /* RxSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxSwift.release.xcconfig; sourceTree = ""; }; + 4C233162E224D042B1A9ADB5FFC75596 /* Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Signal.swift; path = RxCocoa/Traits/Signal/Signal.swift; sourceTree = ""; }; + 4C58CCC55F3E94E451DEEC457570FD6F /* Single.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Single.swift; path = RxSwift/Traits/PrimitiveSequence/Single.swift; sourceTree = ""; }; + 4C710A6E5E7103CF26BF6DA1A3665A55 /* HistoricalScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalScheduler.swift; path = RxSwift/Schedulers/HistoricalScheduler.swift; sourceTree = ""; }; + 4CAE89435EE2619F199768480BA9B3AC /* Sequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sequence.swift; path = RxSwift/Observables/Sequence.swift; sourceTree = ""; }; + 4CD6F37FF01714E62B05CCE204A180FE /* EventMonitor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EventMonitor.swift; path = Source/EventMonitor.swift; sourceTree = ""; }; + 4D8E35604B9593285F8880155599FE4F /* ControlTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlTarget.swift; path = RxCocoa/Common/ControlTarget.swift; sourceTree = ""; }; + 4DE5128DFD130806F20EC429CA451C0C /* Infallible+CombineLatest+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Infallible+CombineLatest+arity.swift"; path = "RxSwift/Traits/Infallible/Infallible+CombineLatest+arity.swift"; sourceTree = ""; }; + 50813D9A78FAA9D509BC9BB9B2F3C28E /* ConcurrentMainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentMainScheduler.swift; path = RxSwift/Schedulers/ConcurrentMainScheduler.swift; sourceTree = ""; }; + 510F8AF367E03012DF0695088BD61156 /* UITabBar+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITabBar+Rx.swift"; path = "RxCocoa/iOS/UITabBar+Rx.swift"; sourceTree = ""; }; + 519B6C10B0C5FCC12A649E8403532674 /* ControlEvent+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlEvent+Driver.swift"; path = "RxCocoa/Traits/Driver/ControlEvent+Driver.swift"; sourceTree = ""; }; + 5296303E7B76C7C449D2CC7E0E000281 /* ControlProperty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlProperty.swift; path = RxCocoa/Traits/ControlProperty.swift; sourceTree = ""; }; + 5425A30F69C058EBD3CECC3192A4A455 /* TailRecursiveSink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TailRecursiveSink.swift; path = RxSwift/Observers/TailRecursiveSink.swift; sourceTree = ""; }; + 54CADC59F472FDD873ECC8AC0334ADF3 /* URLConvertible+URLRequestConvertible.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLConvertible+URLRequestConvertible.swift"; path = "Source/URLConvertible+URLRequestConvertible.swift"; sourceTree = ""; }; + 557F4A5C3A1E88463A559F6771708562 /* Filter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Filter.swift; path = RxSwift/Observables/Filter.swift; sourceTree = ""; }; + 56060B7A57AAEBE6E3946AA4BD3854D5 /* ObserveOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserveOn.swift; path = RxSwift/Observables/ObserveOn.swift; sourceTree = ""; }; + 565261C7427A20C48DEEE1D949EBD371 /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Platform/DataStructures/Bag.swift; sourceTree = ""; }; + 56BCC58210173BBB48CBEEEA55B9A8AC /* RxCollectionViewDataSourcePrefetchingProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourcePrefetchingProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDataSourcePrefetchingProxy.swift; sourceTree = ""; }; + 57446328CADAB2C557D69630490DD5BD /* Map.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Map.swift; path = RxSwift/Observables/Map.swift; sourceTree = ""; }; + 581BAF255A6D18A23D9B2B8586160060 /* SessionDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SessionDelegate.swift; path = Source/SessionDelegate.swift; sourceTree = ""; }; + 581CD3FDB8146C432DAD2AE38AE8596E /* AuthenticationInterceptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AuthenticationInterceptor.swift; path = Source/AuthenticationInterceptor.swift; sourceTree = ""; }; + 593ECDF08EB42221F442B0B0BA4E09EB /* HistoricalSchedulerTimeConverter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalSchedulerTimeConverter.swift; path = RxSwift/Schedulers/HistoricalSchedulerTimeConverter.swift; sourceTree = ""; }; 5A170BBCAFF78F759B451CA2332B8CD9 /* Pods-Instagram-Clone.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Instagram-Clone.release.xcconfig"; sourceTree = ""; }; - 5AC378ACD31FBB65065DB9EEDE4599CA /* MainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MainScheduler.swift; path = RxSwift/Schedulers/MainScheduler.swift; sourceTree = ""; }; - 5AC87BA30AF3E7421DB0DD8D9A73F869 /* Debounce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debounce.swift; path = RxSwift/Observables/Debounce.swift; sourceTree = ""; }; - 5AF6C495B29F03325205155A225A54C3 /* RxNavigationControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxNavigationControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxNavigationControllerDelegateProxy.swift; sourceTree = ""; }; - 5B9AAA50BFDD2E0E8D502F4ABE2600B8 /* NSControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSControl+Rx.swift"; path = "RxCocoa/macOS/NSControl+Rx.swift"; sourceTree = ""; }; - 5EC3A3C876BB6F997AA895DFC1E92134 /* _RXKVOObserver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXKVOObserver.h; path = RxCocoa/Runtime/include/_RXKVOObserver.h; sourceTree = ""; }; - 5F9CFCE6985273F3DE45053967790C1D /* ConcurrentMainScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentMainScheduler.swift; path = RxSwift/Schedulers/ConcurrentMainScheduler.swift; sourceTree = ""; }; - 60D291EF382DFED378C9057592F06218 /* ObservableConvertibleType+Infallible.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+Infallible.swift"; path = "RxSwift/Traits/Infallible/ObservableConvertibleType+Infallible.swift"; sourceTree = ""; }; - 610CD268ADB35154B7AA77C94FDFE206 /* BehaviorRelay+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "BehaviorRelay+Driver.swift"; path = "RxCocoa/Traits/Driver/BehaviorRelay+Driver.swift"; sourceTree = ""; }; - 619F731B252F401E63D0C2EE802F83C5 /* PublishSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PublishSubject.swift; path = RxSwift/Subjects/PublishSubject.swift; sourceTree = ""; }; - 61D33EF3A2C81402ABFD71409496E49F /* Decode.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Decode.swift; path = RxSwift/Observables/Decode.swift; sourceTree = ""; }; - 628BA9925CB8D093E9B8045E627C5FD3 /* Infallible+Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Infallible+Zip+arity.swift"; path = "RxSwift/Traits/Infallible/Infallible+Zip+arity.swift"; sourceTree = ""; }; - 62B3C64FFDCF5AF4054FD532B041ED61 /* Dematerialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Dematerialize.swift; path = RxSwift/Observables/Dematerialize.swift; sourceTree = ""; }; - 63C78B0D2870B348AB740CEAA27C2E74 /* SynchronizedDisposeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedDisposeType.swift; path = RxSwift/Concurrency/SynchronizedDisposeType.swift; sourceTree = ""; }; - 640E4C77D7B6E46FC569C456AF6116A8 /* ObservableConvertibleType+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+Driver.swift"; path = "RxCocoa/Traits/Driver/ObservableConvertibleType+Driver.swift"; sourceTree = ""; }; - 64388E578D1FB97E4DB5775A469337F1 /* RxRelay-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxRelay-dummy.m"; sourceTree = ""; }; - 6788801F19DA52CA8EE23A3201EFCF2F /* Bag+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Bag+Rx.swift"; path = "RxSwift/Extensions/Bag+Rx.swift"; sourceTree = ""; }; - 6878C434F38257C935BFBCB7DEB933CB /* Observable+Bind.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Observable+Bind.swift"; path = "RxCocoa/Common/Observable+Bind.swift"; sourceTree = ""; }; - 6943A86D4C4C86816F275975A3F56777 /* ObservableType+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+Extensions.swift"; path = "RxSwift/ObservableType+Extensions.swift"; sourceTree = ""; }; - 69C99F11DF4D911FF5F58FF99637AEA8 /* Enumerated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Enumerated.swift; path = RxSwift/Observables/Enumerated.swift; sourceTree = ""; }; - 69FE9077C79452DD8408F90206503B5D /* Amb.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Amb.swift; path = RxSwift/Observables/Amb.swift; sourceTree = ""; }; - 6A570E94AC7743F742308E9408C3DEE9 /* Infallible+CombineLatest+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Infallible+CombineLatest+arity.swift"; path = "RxSwift/Traits/Infallible/Infallible+CombineLatest+arity.swift"; sourceTree = ""; }; - 6C6F8A7DAB39B910A381FDC4AC70E3A0 /* RxCocoa.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxCocoa.modulemap; sourceTree = ""; }; - 6C867006979B630B992855A4332250EA /* SwiftLint.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftLint.debug.xcconfig; sourceTree = ""; }; - 6EDA7483F44DEE73680237D089137E9D /* RxRelay-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxRelay-prefix.pch"; sourceTree = ""; }; - 70664A49465BD35C219845778B09404D /* Observable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Observable.swift; path = RxSwift/Observable.swift; sourceTree = ""; }; - 70A24B6007154434755D6FE7829B75E1 /* NSObject+Rx+RawRepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx+RawRepresentable.swift"; path = "RxCocoa/Foundation/NSObject+Rx+RawRepresentable.swift"; sourceTree = ""; }; - 70E0254E101D267C71ECFDB98B9CDD73 /* RxTextStorageDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTextStorageDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTextStorageDelegateProxy.swift; sourceTree = ""; }; - 72046CC8FB967C35B5E0DC3F870678A7 /* Reduce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reduce.swift; path = RxSwift/Observables/Reduce.swift; sourceTree = ""; }; - 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; - 742D5848876230A2E30823D4FDE0FDB0 /* RxRelay-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxRelay-umbrella.h"; sourceTree = ""; }; - 74B7F67BA3B530028F633568D0A7D4CA /* Empty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Empty.swift; path = RxSwift/Observables/Empty.swift; sourceTree = ""; }; - 7561914E2B359EE2F9867B879662FDBE /* Single.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Single.swift; path = RxSwift/Traits/PrimitiveSequence/Single.swift; sourceTree = ""; }; - 75BD1907BE8577B050A2AD8FA2FA7B75 /* AnonymousDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousDisposable.swift; path = RxSwift/Disposables/AnonymousDisposable.swift; sourceTree = ""; }; - 7608E2D33CF20C31B9FA50AF57E5FDF9 /* Throttle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Throttle.swift; path = RxSwift/Observables/Throttle.swift; sourceTree = ""; }; - 761783ACC956844B0C427D1A56C4050C /* DefaultIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DefaultIfEmpty.swift; path = RxSwift/Observables/DefaultIfEmpty.swift; sourceTree = ""; }; - 767BA97D4F49BFF48996CDFDCEDCAAF5 /* CombineLatest+Collection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+Collection.swift"; path = "RxSwift/Observables/CombineLatest+Collection.swift"; sourceTree = ""; }; - 767D94760D69C37D5D5D80715BD2399E /* Generate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Generate.swift; path = RxSwift/Observables/Generate.swift; sourceTree = ""; }; - 777FFBD65C0FF1B4A48D8C459DC31721 /* UISegmentedControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISegmentedControl+Rx.swift"; path = "RxCocoa/iOS/UISegmentedControl+Rx.swift"; sourceTree = ""; }; - 7889CA4E7E7326754FE945E78B60B4B1 /* Filter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Filter.swift; path = RxSwift/Observables/Filter.swift; sourceTree = ""; }; - 791B8B0D9B49A4D288CFDE5AFAC9101F /* ControlEvent+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlEvent+Signal.swift"; path = "RxCocoa/Traits/Signal/ControlEvent+Signal.swift"; sourceTree = ""; }; - 7D24118C234DAAA28D8D06D4DAED823B /* RxCocoaObjCRuntimeError+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "RxCocoaObjCRuntimeError+Extensions.swift"; path = "RxCocoa/Common/RxCocoaObjCRuntimeError+Extensions.swift"; sourceTree = ""; }; - 7D8C3064DA8BE2AD59875B2AA63F7D8A /* Infallible+Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Infallible+Operators.swift"; path = "RxSwift/Traits/Infallible/Infallible+Operators.swift"; sourceTree = ""; }; - 7DF318A6380B535D896F263A1D31A886 /* InvocableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableType.swift; path = RxSwift/Schedulers/Internal/InvocableType.swift; sourceTree = ""; }; - 7E5A11BFD4B2349FE0800D0FEE107B6E /* SwiftLint.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SwiftLint.release.xcconfig; sourceTree = ""; }; - 7E8F125BC91320E99EBE78FEE1309CDA /* RxRelay.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxRelay.release.xcconfig; sourceTree = ""; }; - 7F88262ECD3611A994C7578DF1AC90D3 /* RxCollectionViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDataSourceProxy.swift; sourceTree = ""; }; - 800125918B1A34EEA9B5EBF32842ADC6 /* ControlEvent.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlEvent.swift; path = RxCocoa/Traits/ControlEvent.swift; sourceTree = ""; }; + 5B6CB2FCC481D092A24CD0A922397325 /* RxCocoa.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxCocoa.debug.xcconfig; sourceTree = ""; }; + 5D797E9A5C5782CE845840781FA1CC81 /* Alamofire */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Alamofire; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5ECFFF39AC84FF510A575BBBD6BA4B0A /* HTTPHeaders.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HTTPHeaders.swift; path = Source/HTTPHeaders.swift; sourceTree = ""; }; + 5F38231AE4C38080DF74A2D0BEDD8BCE /* Date+Dispatch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Date+Dispatch.swift"; path = "RxSwift/Date+Dispatch.swift"; sourceTree = ""; }; + 5F43B8F01A543777B15BE6850ED311C5 /* Producer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Producer.swift; path = RxSwift/Observables/Producer.swift; sourceTree = ""; }; + 5F538C639AC1945189EB1CE26FAC6BEF /* RxCocoa-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxCocoa-dummy.m"; sourceTree = ""; }; + 623EBC29B18495CA0C436D827CEE6728 /* Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Driver.swift; path = RxCocoa/Traits/Driver/Driver.swift; sourceTree = ""; }; + 63E36BC902C9ADA7FE3C6397491B5082 /* RxPickerViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxPickerViewDataSourceType.swift; sourceTree = ""; }; + 63E8E04E3E7BD0E30508D61F734DFC14 /* RetryWhen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RetryWhen.swift; path = RxSwift/Observables/RetryWhen.swift; sourceTree = ""; }; + 645A3BDD411B7668A9CB4FF049051177 /* RxRelay-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxRelay-Info.plist"; sourceTree = ""; }; + 64A208A052C3CE6C1240B092E490CAB1 /* InfiniteSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfiniteSequence.swift; path = Platform/DataStructures/InfiniteSequence.swift; sourceTree = ""; }; + 6591215365055B0134F330A97A10C301 /* RxTabBarDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTabBarDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTabBarDelegateProxy.swift; sourceTree = ""; }; + 65FA1855B83C5BE32DA991D72EEA3564 /* MultipartUpload.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MultipartUpload.swift; path = Source/MultipartUpload.swift; sourceTree = ""; }; + 662CE261C0D358E5AE55613422CCDBCB /* Take.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Take.swift; path = RxSwift/Observables/Take.swift; sourceTree = ""; }; + 669DDE6F99F9C873BE8B242EBA224C37 /* _RXKVOObserver.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXKVOObserver.h; path = RxCocoa/Runtime/include/_RXKVOObserver.h; sourceTree = ""; }; + 6A75C1BA7C53C89CFEF1F83EE37E7EE6 /* ControlProperty+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlProperty+Driver.swift"; path = "RxCocoa/Traits/Driver/ControlProperty+Driver.swift"; sourceTree = ""; }; + 6AC71F58A210A9BF7B75395A077BCF53 /* UITableView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITableView+Rx.swift"; path = "RxCocoa/iOS/UITableView+Rx.swift"; sourceTree = ""; }; + 6BC23ED6D414C352E57C88DC42A6022F /* UISlider+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISlider+Rx.swift"; path = "RxCocoa/iOS/UISlider+Rx.swift"; sourceTree = ""; }; + 6CE26D5D8DD5D6141DBE1A83DB70651F /* InvocableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableType.swift; path = RxSwift/Schedulers/Internal/InvocableType.swift; sourceTree = ""; }; + 6DBDD4E2905AB157F4C1B0DDC9AC1A2E /* RxSearchBarDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxSearchBarDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxSearchBarDelegateProxy.swift; sourceTree = ""; }; + 6DCC34277014CFA748F33D63F2B0DDBC /* ConcurrentDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentDispatchQueueScheduler.swift; path = RxSwift/Schedulers/ConcurrentDispatchQueueScheduler.swift; sourceTree = ""; }; + 6E371A1CF57F9459FCB12BC146AF7E84 /* Disposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposable.swift; path = RxSwift/Disposable.swift; sourceTree = ""; }; + 7033B5BDCF5E1938C2218057A72A2ACD /* ScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItem.swift; path = RxSwift/Schedulers/Internal/ScheduledItem.swift; sourceTree = ""; }; + 70932FD1797B63C347443B74252917E8 /* Sample.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sample.swift; path = RxSwift/Observables/Sample.swift; sourceTree = ""; }; + 716C98F332A803D36F35817F3A5E10ED /* SingleAssignmentDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAssignmentDisposable.swift; path = RxSwift/Disposables/SingleAssignmentDisposable.swift; sourceTree = ""; }; + 71C3768A32C06D82A80CB88CF8751FFB /* _RXDelegateProxy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXDelegateProxy.m; path = RxCocoa/Runtime/_RXDelegateProxy.m; sourceTree = ""; }; + 7269D3077B11B2C74F5650E6D52258ED /* NopDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NopDisposable.swift; path = RxSwift/Disposables/NopDisposable.swift; sourceTree = ""; }; + 730E778D74EC5F08A80D328E71B9589A /* InvocableScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableScheduledItem.swift; path = RxSwift/Schedulers/Internal/InvocableScheduledItem.swift; sourceTree = ""; }; + 732036B3E5DD047637BB1B9A777EA1E5 /* RxCollectionViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxCollectionViewDataSourceProxy.swift; sourceTree = ""; }; + 734C97C73C262E10D878B235A0B0B183 /* URLRequest+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLRequest+Alamofire.swift"; path = "Source/URLRequest+Alamofire.swift"; sourceTree = ""; }; + 7388BCBEE8E3D8292F5D6253EE8E2C5E /* HTTPMethod.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HTTPMethod.swift; path = Source/HTTPMethod.swift; sourceTree = ""; }; + 75194C640C0A0483CC26C0CFC3517506 /* First.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = First.swift; path = RxSwift/Observables/First.swift; sourceTree = ""; }; + 75F81D96A7B42E852FC0270A81AD5765 /* Disposables.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposables.swift; path = RxSwift/Disposables/Disposables.swift; sourceTree = ""; }; + 768133F2C2CC8674F7220CD20CBC738C /* RxTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTarget.swift; path = RxCocoa/Common/RxTarget.swift; sourceTree = ""; }; + 77B8D452A0987A391C116266CC693A6F /* Infallible+Bind.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Infallible+Bind.swift"; path = "RxCocoa/Common/Infallible+Bind.swift"; sourceTree = ""; }; + 7887DA93F3CD7EF16FBDAF60F9A0C6A7 /* ControlEvent+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlEvent+Signal.swift"; path = "RxCocoa/Traits/Signal/ControlEvent+Signal.swift"; sourceTree = ""; }; + 78CCC4722D47EFB9F36D15D6075781DB /* TakeWithPredicate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeWithPredicate.swift; path = RxSwift/Observables/TakeWithPredicate.swift; sourceTree = ""; }; + 7A3DD3E4A9A4673B47D4C6BB1ECC2FE8 /* BehaviorRelay+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "BehaviorRelay+Driver.swift"; path = "RxCocoa/Traits/Driver/BehaviorRelay+Driver.swift"; sourceTree = ""; }; + 7B6279D00F667A0057801EF3AB863202 /* ElementAt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ElementAt.swift; path = RxSwift/Observables/ElementAt.swift; sourceTree = ""; }; + 7C9BC0E9772C9C6C7981B6B3A3663C06 /* Multicast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Multicast.swift; path = RxSwift/Observables/Multicast.swift; sourceTree = ""; }; + 7CFB93251A99DD08018B991E538ADD37 /* SynchronizedOnType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedOnType.swift; path = RxSwift/Concurrency/SynchronizedOnType.swift; sourceTree = ""; }; + 7EAE90FF45150043BC9B9FFA197B7213 /* AsSingle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsSingle.swift; path = RxSwift/Observables/AsSingle.swift; sourceTree = ""; }; + 7F3AD1EC697290EA4E4FAC118C308D98 /* Infallible+Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Infallible+Zip+arity.swift"; path = "RxSwift/Traits/Infallible/Infallible+Zip+arity.swift"; sourceTree = ""; }; + 801EA459B5D61FCD65C817EB048EAB29 /* PublishSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PublishSubject.swift; path = RxSwift/Subjects/PublishSubject.swift; sourceTree = ""; }; 809C5FAB588354C9BA37DC3EAB8CB45C /* RxSwift */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RxSwift; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 80F107C23AD0B22789290606EDE7C423 /* SynchronizedUnsubscribeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedUnsubscribeType.swift; path = RxSwift/Concurrency/SynchronizedUnsubscribeType.swift; sourceTree = ""; }; - 82BA61FA49C436947F13F9CE34C37C91 /* RxSearchControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxSearchControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxSearchControllerDelegateProxy.swift; sourceTree = ""; }; + 8105F1AED97EBB31E9ECE90220331050 /* Platform.Darwin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Darwin.swift; path = Platform/Platform.Darwin.swift; sourceTree = ""; }; + 81A38A41FF433485F61118C92056AB27 /* ObservableConvertibleType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableConvertibleType.swift; path = RxSwift/ObservableConvertibleType.swift; sourceTree = ""; }; 832600334A0B039D6270E3CE9FDCF8F8 /* Pods-Instagram-Clone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Instagram-Clone.debug.xcconfig"; sourceTree = ""; }; - 8403ABA7A5EF2EC532F05258F9862B4B /* SharedSequence+Operators+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SharedSequence+Operators+arity.swift"; path = "RxCocoa/Traits/SharedSequence/SharedSequence+Operators+arity.swift"; sourceTree = ""; }; - 87911FA9E065451BD946DC5DF3C59D3C /* AnyObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnyObserver.swift; path = RxSwift/AnyObserver.swift; sourceTree = ""; }; - 8892F4474BA4B9852E09846DC7B861F0 /* BinaryDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BinaryDisposable.swift; path = RxSwift/Disposables/BinaryDisposable.swift; sourceTree = ""; }; - 898AC549FA3207BF3C86263F8BEC9241 /* TailRecursiveSink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TailRecursiveSink.swift; path = RxSwift/Observers/TailRecursiveSink.swift; sourceTree = ""; }; - 8A0B47045699682A1F80DB7EC82EF7EC /* First.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = First.swift; path = RxSwift/Observables/First.swift; sourceTree = ""; }; + 83EE95F979FACA89F44D68CC3489DE8F /* UICollectionView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UICollectionView+Rx.swift"; path = "RxCocoa/iOS/UICollectionView+Rx.swift"; sourceTree = ""; }; + 844031D7991F5389D65BF8E22D318F9D /* SharedSequence+Operators+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SharedSequence+Operators+arity.swift"; path = "RxCocoa/Traits/SharedSequence/SharedSequence+Operators+arity.swift"; sourceTree = ""; }; + 852B8D3959EFB94CF388478FD427AA2C /* Infallible+Create.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Infallible+Create.swift"; path = "RxSwift/Traits/Infallible/Infallible+Create.swift"; sourceTree = ""; }; + 86E5EFE7C6AF249A0542C9D41215F5FE /* URLSession+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLSession+Rx.swift"; path = "RxCocoa/Foundation/URLSession+Rx.swift"; sourceTree = ""; }; + 871FB5539265859CC8CC49821EC0DE38 /* Debounce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debounce.swift; path = RxSwift/Observables/Debounce.swift; sourceTree = ""; }; + 89DE6A4A58CC9CBDADB822DD004594A0 /* RxCocoa.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxCocoa.release.xcconfig; sourceTree = ""; }; + 89EACE9FD0C33F1B6B27CC836BDBE706 /* UIGestureRecognizer+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIGestureRecognizer+Rx.swift"; path = "RxCocoa/iOS/UIGestureRecognizer+Rx.swift"; sourceTree = ""; }; 8A126E0270200C843AF51E993B2E277F /* Pods-Instagram-Clone */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-Instagram-Clone"; path = Pods_Instagram_Clone.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 8A35B44531A4D80CEAB2B91D2C3B1F93 /* _RXKVOObserver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXKVOObserver.m; path = RxCocoa/Runtime/_RXKVOObserver.m; sourceTree = ""; }; - 8A4ABC1DD59390FF09893BFC0EDECA6C /* SerialDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDisposable.swift; path = RxSwift/Disposables/SerialDisposable.swift; sourceTree = ""; }; - 8CA2662060A6EFE096AA3BB117ABF465 /* Infallible.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Infallible.swift; path = RxSwift/Traits/Infallible/Infallible.swift; sourceTree = ""; }; - 8DE31BF75E95FE12CF6EB3E9941E03E7 /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Extensions.swift"; path = "Platform/DispatchQueue+Extensions.swift"; sourceTree = ""; }; - 90009E81E181BC430376EC477FF1561B /* Skip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Skip.swift; path = RxSwift/Observables/Skip.swift; sourceTree = ""; }; - 9044811BD3FCD91090DAAB658671FE6A /* SwitchIfEmpty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SwitchIfEmpty.swift; path = RxSwift/Observables/SwitchIfEmpty.swift; sourceTree = ""; }; - 90BFC489D14E1BB573EDC77B78300C58 /* Disposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposable.swift; path = RxSwift/Disposable.swift; sourceTree = ""; }; - 9251013E40AF2901CABD2FC73CBE7614 /* UITableView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITableView+Rx.swift"; path = "RxCocoa/iOS/UITableView+Rx.swift"; sourceTree = ""; }; - 9255CBB2D0BDBAB46779F2BE12C9834B /* WKWebView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "WKWebView+Rx.swift"; path = "RxCocoa/iOS/WKWebView+Rx.swift"; sourceTree = ""; }; - 92A7E4BD7E45FB638F049D2CF3272D20 /* Lock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Lock.swift; path = RxSwift/Concurrency/Lock.swift; sourceTree = ""; }; - 92E5B6359027EBC6DEC81A16B89FBBAB /* StartWith.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StartWith.swift; path = RxSwift/Observables/StartWith.swift; sourceTree = ""; }; - 935118C1700F1FBAF0850D84AC0BF44A /* DisposeBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBase.swift; path = RxSwift/Disposables/DisposeBase.swift; sourceTree = ""; }; - 944D4A34E4D244179DE134F59EFA997C /* UICollectionView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UICollectionView+Rx.swift"; path = "RxCocoa/iOS/UICollectionView+Rx.swift"; sourceTree = ""; }; - 94A493DBC8176AF0EE6C485A647C930F /* UITabBar+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITabBar+Rx.swift"; path = "RxCocoa/iOS/UITabBar+Rx.swift"; sourceTree = ""; }; - 9584F2AD1F12E0E0F15B714F0CC6E68F /* AsMaybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsMaybe.swift; path = RxSwift/Observables/AsMaybe.swift; sourceTree = ""; }; - 95A778976F3DF4C3E0BE8CFF8FFA3DCE /* InvocableScheduledItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InvocableScheduledItem.swift; path = RxSwift/Schedulers/Internal/InvocableScheduledItem.swift; sourceTree = ""; }; - 96F124CB1F0EEFE46E9400A8A5A771D5 /* ShareReplayScope.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ShareReplayScope.swift; path = RxSwift/Observables/ShareReplayScope.swift; sourceTree = ""; }; - 97582CE90B36CC35E3344E0B3BB9E8C2 /* RxScrollViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxScrollViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxScrollViewDelegateProxy.swift; sourceTree = ""; }; - 97A6F4201F3E82652819407100545509 /* LockOwnerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LockOwnerType.swift; path = RxSwift/Concurrency/LockOwnerType.swift; sourceTree = ""; }; - 99D05E0077CF60BFE82F418F41B62749 /* Platform.Linux.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Linux.swift; path = Platform/Platform.Linux.swift; sourceTree = ""; }; - 9AE802EE93AC891F8BBD3595F4F97123 /* RxCocoa.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxCocoa.release.xcconfig; sourceTree = ""; }; - 9B83A6E4784CADA73C8A18D843D3AA5E /* SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SharedSequence.swift; path = RxCocoa/Traits/SharedSequence/SharedSequence.swift; sourceTree = ""; }; - 9BD7648ABD334379BE8CD01DF07615E6 /* RxRelay-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxRelay-Info.plist"; sourceTree = ""; }; - 9D0818786883B7E84DC3216C80C0F342 /* ImmediateSchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImmediateSchedulerType.swift; path = RxSwift/ImmediateSchedulerType.swift; sourceTree = ""; }; - 9D6DBC599BD63D72D8E840C6A338EFFE /* UIButton+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIButton+Rx.swift"; path = "RxCocoa/iOS/UIButton+Rx.swift"; sourceTree = ""; }; - 9D7F8F13AF4282C1D19D4B2E42A5FDE3 /* Materialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Materialize.swift; path = RxSwift/Observables/Materialize.swift; sourceTree = ""; }; + 8B44EDE211FB067BAA8C79521F169355 /* ObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableType.swift; path = RxSwift/ObservableType.swift; sourceTree = ""; }; + 8B6565DBDAB6E638F9B180AC2B084B0E /* URLEncodedFormEncoder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = URLEncodedFormEncoder.swift; path = Source/URLEncodedFormEncoder.swift; sourceTree = ""; }; + 8CAA0879259D2329E9EE3AB59EE9202D /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Extensions.swift"; path = "Platform/DispatchQueue+Extensions.swift"; sourceTree = ""; }; + 8D165677590A732F5E46A334914AF9F1 /* Range.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Range.swift; path = RxSwift/Observables/Range.swift; sourceTree = ""; }; + 8D3D57353834825F7B52B816066B7789 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; + 8DFCC0632F76CF0BA9C49B9A2B33DF57 /* BehaviorRelay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BehaviorRelay.swift; path = RxRelay/BehaviorRelay.swift; sourceTree = ""; }; + 8E48048F9DE3CE9CDFD07D96C43092EB /* Just.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Just.swift; path = RxSwift/Observables/Just.swift; sourceTree = ""; }; + 8EE39E5285C895DFB30377387C2BC245 /* PrimitiveSequence+Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PrimitiveSequence+Zip+arity.swift"; path = "RxSwift/Traits/PrimitiveSequence/PrimitiveSequence+Zip+arity.swift"; sourceTree = ""; }; + 8EF52747268CDA52F3EB2AD2E9D3A4DF /* RxRelay-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxRelay-prefix.pch"; sourceTree = ""; }; + 8F188F3631ABA83DC4520B28431AF8E1 /* ObservableConvertibleType+SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+SharedSequence.swift"; path = "RxCocoa/Traits/SharedSequence/ObservableConvertibleType+SharedSequence.swift"; sourceTree = ""; }; + 8F1E1808D922AA079EF80B4EF1349FBF /* SubscribeOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscribeOn.swift; path = RxSwift/Observables/SubscribeOn.swift; sourceTree = ""; }; + 8F4EC36A54010622D3E1DBAF1CE07365 /* RxTableViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxTableViewDataSourceType.swift; sourceTree = ""; }; + 8FC6857CE4BA0536407B134EE1028C0D /* MultipartFormData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MultipartFormData.swift; path = Source/MultipartFormData.swift; sourceTree = ""; }; + 90437FAB08E287AE379C7C8CFACED79F /* SchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SchedulerType.swift; path = RxSwift/SchedulerType.swift; sourceTree = ""; }; + 9193A575AD5A353845C82E257E9E18FB /* Bag+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Bag+Rx.swift"; path = "RxSwift/Extensions/Bag+Rx.swift"; sourceTree = ""; }; + 91CA9BD79C42A139D0C8431BDFDA3223 /* RxTextStorageDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTextStorageDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTextStorageDelegateProxy.swift; sourceTree = ""; }; + 923E4FEB8C92DE3B193F1BEFF1FAFA36 /* AddRef.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AddRef.swift; path = RxSwift/Observables/AddRef.swift; sourceTree = ""; }; + 93D9788DA7EEE3354ABA2E15C9D71728 /* Never.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Never.swift; path = RxSwift/Observables/Never.swift; sourceTree = ""; }; + 93DB2AFE7188A1E1A53B376DF03ED898 /* RxCocoa-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxCocoa-umbrella.h"; sourceTree = ""; }; + 94E20CB67BEF87997F5C88B67D4165B1 /* _RXKVOObserver.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RXKVOObserver.m; path = RxCocoa/Runtime/_RXKVOObserver.m; sourceTree = ""; }; + 953C63177619AB342C34EEE783C81EF8 /* RecursiveLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveLock.swift; path = Platform/RecursiveLock.swift; sourceTree = ""; }; + 95499D30AF1F2DE7A7CEA8AA0DBB0B3C /* DelegateProxyType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelegateProxyType.swift; path = RxCocoa/Common/DelegateProxyType.swift; sourceTree = ""; }; + 970FA5A266DB2924BBD2B982F74412EA /* RxCollectionViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxCollectionViewDataSourceType.swift; sourceTree = ""; }; + 97A8FF5FA28E690E10D289E1D57F7930 /* ParameterEncoder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParameterEncoder.swift; path = Source/ParameterEncoder.swift; sourceTree = ""; }; + 980E21F4EE794E4E1FF3E33D6882A259 /* Generate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Generate.swift; path = RxSwift/Observables/Generate.swift; sourceTree = ""; }; + 993CAA60E070CF39B9426C3F90BD63E3 /* Reduce.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reduce.swift; path = RxSwift/Observables/Reduce.swift; sourceTree = ""; }; + 9B68E008BBF20F4741848EDDF2B82A6A /* RxSwift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxSwift-Info.plist"; sourceTree = ""; }; + 9CC6DB2A76E65928E8309796E3B4EC66 /* RxSwift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxSwift.modulemap; sourceTree = ""; }; 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - 9D9880E80FCAA42588A804BA350064BE /* UIStepper+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIStepper+Rx.swift"; path = "RxCocoa/iOS/UIStepper+Rx.swift"; sourceTree = ""; }; - 9E98442EE02EEDF78B15D2F6A5168DDA /* RxSwift.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxSwift.release.xcconfig; sourceTree = ""; }; - 9EAF3426B2E09A3FD26E570F5435C1C4 /* Sequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sequence.swift; path = RxSwift/Observables/Sequence.swift; sourceTree = ""; }; - 9F09AB4C59893AD412B9A8974A44EFAF /* GroupedObservable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupedObservable.swift; path = RxSwift/GroupedObservable.swift; sourceTree = ""; }; - 9F533CB02A453B09B128C0121F309F99 /* ObserveOn.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserveOn.swift; path = RxSwift/Observables/ObserveOn.swift; sourceTree = ""; }; - A0580CAACDB221AEAEF5EE46900A661E /* BehaviorRelay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BehaviorRelay.swift; path = RxRelay/BehaviorRelay.swift; sourceTree = ""; }; - A0A7DD927A1CA40ACB4A31136448C7B6 /* Reactive.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Reactive.swift; path = RxSwift/Reactive.swift; sourceTree = ""; }; - A175A343983FD9CE1E9FA110FB2F40D8 /* ControlTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlTarget.swift; path = RxCocoa/Common/ControlTarget.swift; sourceTree = ""; }; - A3399CFBB1396ACD6286EBA4D81D4D0C /* AnonymousObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousObserver.swift; path = RxSwift/Observers/AnonymousObserver.swift; sourceTree = ""; }; - A49C6178A71EBA0C7BE086BDE5ED1E66 /* RxTabBarDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTabBarDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTabBarDelegateProxy.swift; sourceTree = ""; }; + A0EB2A699BBE7A22239A58AD031BB825 /* RxCocoa-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "RxCocoa-Info.plist"; sourceTree = ""; }; + A18BC45336950B8C433FD02E847AD38F /* UISearchController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISearchController+Rx.swift"; path = "RxCocoa/iOS/UISearchController+Rx.swift"; sourceTree = ""; }; + A360A1E748495A656A23264F856CCF30 /* Alamofire.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Alamofire.debug.xcconfig; sourceTree = ""; }; A508E25E6E16C0FD2CFCB6D9D87AC2E2 /* Pods-Instagram-Clone-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Instagram-Clone-acknowledgements.plist"; sourceTree = ""; }; - A6F2C49E08301D6E1CC8CAC4EB7B5905 /* SharedSequence+Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SharedSequence+Operators.swift"; path = "RxCocoa/Traits/SharedSequence/SharedSequence+Operators.swift"; sourceTree = ""; }; - A6FDDF83812BC79A312D7CCA6CD16F3A /* RecursiveLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveLock.swift; path = Platform/RecursiveLock.swift; sourceTree = ""; }; A70211BEDFBEEA826F0F36F981DCCF6D /* Pods-Instagram-Clone-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Instagram-Clone-acknowledgements.markdown"; sourceTree = ""; }; - A7A312365200557E6349C200AA39470A /* PublishRelay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PublishRelay.swift; path = RxRelay/PublishRelay.swift; sourceTree = ""; }; - A7CF4533A429B848A2569FE826DFC277 /* Queue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = Platform/DataStructures/Queue.swift; sourceTree = ""; }; - A8C4AF57E2F918529D2AF398E1E5CDFB /* ConcurrentDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConcurrentDispatchQueueScheduler.swift; path = RxSwift/Schedulers/ConcurrentDispatchQueueScheduler.swift; sourceTree = ""; }; - A9D4D718EE79B06EF7DA68A039598B40 /* Producer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Producer.swift; path = RxSwift/Observables/Producer.swift; sourceTree = ""; }; - A9E3A902E1F2FE5A95218F7934C84C30 /* AsyncSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncSubject.swift; path = RxSwift/Subjects/AsyncSubject.swift; sourceTree = ""; }; - AA218DB75EBB15A3A1EF4327B71DC923 /* Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Signal.swift; path = RxCocoa/Traits/Signal/Signal.swift; sourceTree = ""; }; - AC6807AD4C1E67D2C647316CD0ACFE54 /* Disposables.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Disposables.swift; path = RxSwift/Disposables/Disposables.swift; sourceTree = ""; }; - ACB0E157337542EC91EA1D85D49A693E /* NSTextView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextView+Rx.swift"; path = "RxCocoa/macOS/NSTextView+Rx.swift"; sourceTree = ""; }; - AD8DB1146C2FD3850E2DC90065612219 /* Debug.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debug.swift; path = RxSwift/Observables/Debug.swift; sourceTree = ""; }; - AF22661CDDC03ED4086D034894D7C105 /* Signal+Subscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Signal+Subscription.swift"; path = "RxCocoa/Traits/Signal/Signal+Subscription.swift"; sourceTree = ""; }; - AF77625DB712A38BD99168A49606C55F /* RxSwift.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxSwift.debug.xcconfig; sourceTree = ""; }; + A82B59C46A8891A0AF7A544DDCDBE7A4 /* _RXDelegateProxy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXDelegateProxy.h; path = RxCocoa/Runtime/include/_RXDelegateProxy.h; sourceTree = ""; }; + A8BB59E8726483F52D6D6971BCC1B3B8 /* CombineLatest+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "CombineLatest+arity.swift"; path = "RxSwift/Observables/CombineLatest+arity.swift"; sourceTree = ""; }; + A8BD652C0FF5C63E1A0B2F5394B2AA62 /* Alamofire.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Alamofire.modulemap; sourceTree = ""; }; + A97D6619DD182B507FB857AD61304B44 /* SchedulerType+SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SchedulerType+SharedSequence.swift"; path = "RxCocoa/Traits/SharedSequence/SchedulerType+SharedSequence.swift"; sourceTree = ""; }; + AA8EBC7BECC7DD0598F14332FCC97995 /* ServerTrustEvaluation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ServerTrustEvaluation.swift; path = Source/ServerTrustEvaluation.swift; sourceTree = ""; }; + AAD641B0D7B200397821BB739A168DD1 /* NSView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSView+Rx.swift"; path = "RxCocoa/macOS/NSView+Rx.swift"; sourceTree = ""; }; + AB37CF81A092A3E976BE535DB38A6964 /* PriorityQueue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PriorityQueue.swift; path = Platform/DataStructures/PriorityQueue.swift; sourceTree = ""; }; + AD15E723F2844714489FFB45590ABD63 /* Sink.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Sink.swift; path = RxSwift/Observables/Sink.swift; sourceTree = ""; }; + ADFAD819AD24E96A15E4C119C4BDFE0C /* RxCocoa.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxCocoa.modulemap; sourceTree = ""; }; + AEFA60C5F16D18879D7BA1A6092A068A /* RxMutableBox.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxMutableBox.swift; path = RxSwift/RxMutableBox.swift; sourceTree = ""; }; + AF03C202E24C0B84A8025CA0E8FFFDBC /* AtomicInt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AtomicInt.swift; path = Platform/AtomicInt.swift; sourceTree = ""; }; + AF5C52B068668E86B1D259B8C141CBE7 /* AsyncSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsyncSubject.swift; path = RxSwift/Subjects/AsyncSubject.swift; sourceTree = ""; }; + AFA0FDF7B29DB45C9207791DA9305107 /* Combine.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Combine.swift; path = Source/Combine.swift; sourceTree = ""; }; + AFDC49E2EA080C69C9A651D20A8D625C /* Create.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Create.swift; path = RxSwift/Observables/Create.swift; sourceTree = ""; }; AFF08FF98C2047D7556547EBFB9C46E4 /* Pods-Instagram-Clone-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Instagram-Clone-frameworks.sh"; sourceTree = ""; }; - B06D287CBC4CC7C094B544F533F4CA65 /* Observable+Bind.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Observable+Bind.swift"; path = "RxRelay/Observable+Bind.swift"; sourceTree = ""; }; - B09EC6A25D0F81AE425C42CE3E04DF34 /* Optional.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Optional.swift; path = RxSwift/Observables/Optional.swift; sourceTree = ""; }; - B129863F6D3DDCF8834A7AA74F387E92 /* RxPickerViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxPickerViewDataSourceProxy.swift; sourceTree = ""; }; - B1D7D698F8E89D6A74D2068A57CD9019 /* ObservableType+PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+PrimitiveSequence.swift"; path = "RxSwift/Traits/PrimitiveSequence/ObservableType+PrimitiveSequence.swift"; sourceTree = ""; }; - B1ED315F78613719616BD46F58A69425 /* TakeWithPredicate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeWithPredicate.swift; path = RxSwift/Observables/TakeWithPredicate.swift; sourceTree = ""; }; - B2825DBF5B8A8DF6608934526497046A /* RxTableViewDataSourceType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourceType.swift; path = RxCocoa/iOS/Protocols/RxTableViewDataSourceType.swift; sourceTree = ""; }; - B2B24E3FC4E0E31678BE3D07FE5B5546 /* Do.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Do.swift; path = RxSwift/Observables/Do.swift; sourceTree = ""; }; - B30D4AF1264D8B0677474E3A66F22172 /* ObservableType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableType.swift; path = RxSwift/ObservableType.swift; sourceTree = ""; }; - B344BFC1C0D14E36B199F98E6172B040 /* UISearchBar+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISearchBar+Rx.swift"; path = "RxCocoa/iOS/UISearchBar+Rx.swift"; sourceTree = ""; }; - B35CAAC7C2C89492E1A53DE25F9C8C35 /* UITextField+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITextField+Rx.swift"; path = "RxCocoa/iOS/UITextField+Rx.swift"; sourceTree = ""; }; - B3E1DA0ABC944D798284B02ACCA2ACFA /* Switch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Switch.swift; path = RxSwift/Observables/Switch.swift; sourceTree = ""; }; - B40E371D7A6BBFB7E8FE61981378D673 /* Platform.Darwin.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Darwin.swift; path = Platform/Platform.Darwin.swift; sourceTree = ""; }; - B810010130BCEDC6EFDBEFAA3F5E138F /* PrimitiveSequence+Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PrimitiveSequence+Zip+arity.swift"; path = "RxSwift/Traits/PrimitiveSequence/PrimitiveSequence+Zip+arity.swift"; sourceTree = ""; }; - B9080BDB30A4F4776904377290A3551C /* RxTableViewDataSourceProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDataSourceProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDataSourceProxy.swift; sourceTree = ""; }; - BA422B8B653925DECD10A82F5864031D /* UITextView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITextView+Rx.swift"; path = "RxCocoa/iOS/UITextView+Rx.swift"; sourceTree = ""; }; - BABD7A761EC023576B1B30D011691A99 /* RxCocoa.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCocoa.swift; path = RxCocoa/RxCocoa.swift; sourceTree = ""; }; + B001EE5D9F141B15F1B524D9D1CE6FF5 /* RefCountDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RefCountDisposable.swift; path = RxSwift/Disposables/RefCountDisposable.swift; sourceTree = ""; }; + B06E8014F3D0084CBB2E358F32E9DEFF /* SynchronizedUnsubscribeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedUnsubscribeType.swift; path = RxSwift/Concurrency/SynchronizedUnsubscribeType.swift; sourceTree = ""; }; + B0A7A8B1E275B8F3D59D65566FA08C2D /* Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Rx.swift; path = RxSwift/Rx.swift; sourceTree = ""; }; + B0C41ED95427AF71D36B4F084BE5A6AE /* KVORepresentable+CoreGraphics.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "KVORepresentable+CoreGraphics.swift"; path = "RxCocoa/Foundation/KVORepresentable+CoreGraphics.swift"; sourceTree = ""; }; + B2798ACEB5A9F3BB777E6E657288583C /* ControlEvent.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ControlEvent.swift; path = RxCocoa/Traits/ControlEvent.swift; sourceTree = ""; }; + B2AB38E402838475B1BDA2DE7834D96B /* NSTextView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextView+Rx.swift"; path = "RxCocoa/macOS/NSTextView+Rx.swift"; sourceTree = ""; }; + B417BFB59BD825253EAED7DD8806D519 /* NSObject+Rx+RawRepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx+RawRepresentable.swift"; path = "RxCocoa/Foundation/NSObject+Rx+RawRepresentable.swift"; sourceTree = ""; }; + B476816821E0315922ED7A6B7540AFB3 /* PublishRelay+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PublishRelay+Signal.swift"; path = "RxCocoa/Traits/Signal/PublishRelay+Signal.swift"; sourceTree = ""; }; + B5B304BD966D13EF655D5CC30AF30CB3 /* RxSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxSwift-dummy.m"; sourceTree = ""; }; + B63E8E74CB465ACEDD8871E750E708C5 /* BehaviorSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BehaviorSubject.swift; path = RxSwift/Subjects/BehaviorSubject.swift; sourceTree = ""; }; + B766558A6AFFF5D989A09741CD470BA7 /* TextInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TextInput.swift; path = RxCocoa/Common/TextInput.swift; sourceTree = ""; }; + B82686D2BD45E21F1DB076390F8B0F25 /* NSTextField+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextField+Rx.swift"; path = "RxCocoa/macOS/NSTextField+Rx.swift"; sourceTree = ""; }; + B918B07799B36CAEBE63F7D83D7839D5 /* DistinctUntilChanged.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DistinctUntilChanged.swift; path = RxSwift/Observables/DistinctUntilChanged.swift; sourceTree = ""; }; + B958A400ABDE65E1B6A2F557B519841D /* UITextView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITextView+Rx.swift"; path = "RxCocoa/iOS/UITextView+Rx.swift"; sourceTree = ""; }; + B961666FBD681C6B13B784C18D575465 /* RxCocoa.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = RxCocoa.h; path = RxCocoa/RxCocoa.h; sourceTree = ""; }; BC432FD48A5932251F1CAFBC4BF74894 /* RxCocoa */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RxCocoa; path = RxCocoa.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - BD16B00CC1673ECEB6115FAC902E0B56 /* Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+arity.swift"; path = "RxSwift/Observables/Zip+arity.swift"; sourceTree = ""; }; - BD83661C7D461B34B59CBA67D428938E /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = RxSwift/Errors.swift; sourceTree = ""; }; - BE159A12F2C43C59116A33FFB85E05D6 /* ControlEvent+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlEvent+Driver.swift"; path = "RxCocoa/Traits/Driver/ControlEvent+Driver.swift"; sourceTree = ""; }; - BE780295A25F4BCABC879D1536A3C54E /* _RX.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RX.h; path = RxCocoa/Runtime/include/_RX.h; sourceTree = ""; }; - BF284C36287FCF12DED05CABACB2BA82 /* ObserverBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverBase.swift; path = RxSwift/Observers/ObserverBase.swift; sourceTree = ""; }; - C1ED4EBF7B0699C1CE93E1628B4EA1B8 /* RxTextViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTextViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTextViewDelegateProxy.swift; sourceTree = ""; }; - C255FF4F123BF4ECE7E8A1C5821F51FF /* CompositeDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompositeDisposable.swift; path = RxSwift/Disposables/CompositeDisposable.swift; sourceTree = ""; }; - C26426EBCCB55CA8014D9D34B51CFE06 /* RecursiveLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveLock.swift; path = Platform/RecursiveLock.swift; sourceTree = ""; }; - C350F7C7118DA156B0CBF3C4725BB1E2 /* SerialDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDispatchQueueScheduler.swift; path = RxSwift/Schedulers/SerialDispatchQueueScheduler.swift; sourceTree = ""; }; - C37D5F564EE6CB890C291313BEE75AA2 /* SchedulerType+SharedSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "SchedulerType+SharedSequence.swift"; path = "RxCocoa/Traits/SharedSequence/SchedulerType+SharedSequence.swift"; sourceTree = ""; }; - C49739CC03AC63404753D77D10DED8B2 /* NSTextStorage+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextStorage+Rx.swift"; path = "RxCocoa/iOS/NSTextStorage+Rx.swift"; sourceTree = ""; }; - C4A85B1C742FF6712B8AB28B47273634 /* NSSlider+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSSlider+Rx.swift"; path = "RxCocoa/macOS/NSSlider+Rx.swift"; sourceTree = ""; }; + BD18805FCE30E1005F6FC4198C5ED48E /* RxRelay-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxRelay-umbrella.h"; sourceTree = ""; }; + BD8422862D3A378F92CAE72A63E771CC /* Decode.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Decode.swift; path = RxSwift/Observables/Decode.swift; sourceTree = ""; }; + BDED6E55DC07C9A13486397B32A789B8 /* UIDatePicker+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIDatePicker+Rx.swift"; path = "RxCocoa/iOS/UIDatePicker+Rx.swift"; sourceTree = ""; }; + BFC3BE7AF4B17BE5C089702D819FCC4D /* WithLatestFrom.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WithLatestFrom.swift; path = RxSwift/Observables/WithLatestFrom.swift; sourceTree = ""; }; + C10859DDF0B86C7AB30D77FC23A13C38 /* RequestInterceptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RequestInterceptor.swift; path = Source/RequestInterceptor.swift; sourceTree = ""; }; + C181BCCEF5CFDF4873D117F1CE6E1BA4 /* UISearchBar+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISearchBar+Rx.swift"; path = "RxCocoa/iOS/UISearchBar+Rx.swift"; sourceTree = ""; }; + C184367820F49866C61F406AD3D62154 /* UITabBarController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UITabBarController+Rx.swift"; path = "RxCocoa/iOS/UITabBarController+Rx.swift"; sourceTree = ""; }; + C260175CDEEFDC2E0924E1EC569B22CB /* ScheduledItemType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledItemType.swift; path = RxSwift/Schedulers/Internal/ScheduledItemType.swift; sourceTree = ""; }; + C26A34586BB25C239B0C93295410D6B7 /* ItemEvents.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ItemEvents.swift; path = RxCocoa/iOS/Events/ItemEvents.swift; sourceTree = ""; }; + C2BF8546CFD71D9F507D96AF1C570539 /* CombineLatest.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombineLatest.swift; path = RxSwift/Observables/CombineLatest.swift; sourceTree = ""; }; + C2BFEA63DFDBE33D8A71974A9D6C7CEC /* Observable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Observable.swift; path = RxSwift/Observable.swift; sourceTree = ""; }; + C3C8550C0F6D06103D8A56924D191475 /* Merge.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Merge.swift; path = RxSwift/Observables/Merge.swift; sourceTree = ""; }; + C41B899C63FF345426E1B52A8A627AF6 /* UISwitch+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISwitch+Rx.swift"; path = "RxCocoa/iOS/UISwitch+Rx.swift"; sourceTree = ""; }; C4E2F629E6629BB14C3AA2C13A4D05EE /* Pods-Instagram-Clone-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Instagram-Clone-umbrella.h"; sourceTree = ""; }; - C591B3A68D801DC242DC1D3987FEE92F /* NopDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NopDisposable.swift; path = RxSwift/Disposables/NopDisposable.swift; sourceTree = ""; }; - C66DA023B9D646DC6A225AB65C154D7B /* DisposeBag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBag.swift; path = RxSwift/Disposables/DisposeBag.swift; sourceTree = ""; }; - C916D4DC300F09C2F9BA2F32539A274C /* UISearchController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISearchController+Rx.swift"; path = "RxCocoa/iOS/UISearchController+Rx.swift"; sourceTree = ""; }; - CD24ADA98445D4184D06F84FC41D11E7 /* PublishRelay+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "PublishRelay+Signal.swift"; path = "RxCocoa/Traits/Signal/PublishRelay+Signal.swift"; sourceTree = ""; }; - CE7897050459FE64BF884DD0F493CCD2 /* ScheduledDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledDisposable.swift; path = RxSwift/Disposables/ScheduledDisposable.swift; sourceTree = ""; }; - CF7CFF4144277E2FAAAB06F989F256D1 /* RxTabBarControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTabBarControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTabBarControllerDelegateProxy.swift; sourceTree = ""; }; - CFBE22268708B2C3228C3D3C3F89C570 /* RxSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-umbrella.h"; sourceTree = ""; }; - D174A224B1906B2C2C1AFC4A244D0D7E /* Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Driver.swift; path = RxCocoa/Traits/Driver/Driver.swift; sourceTree = ""; }; - D2C1D6D0DAE2CE5850872E7FC3538FCF /* RxSwift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "RxSwift-dummy.m"; sourceTree = ""; }; - D2C66B37865A7C240E9B137458195DBA /* Merge.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Merge.swift; path = RxSwift/Observables/Merge.swift; sourceTree = ""; }; - D3A5DBD1144DF1DE9D79D0DE0FD9FF9C /* UIControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIControl+Rx.swift"; path = "RxCocoa/iOS/UIControl+Rx.swift"; sourceTree = ""; }; - D3A723B60F3BBCF212075132049E83DF /* ObserverType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverType.swift; path = RxSwift/ObserverType.swift; sourceTree = ""; }; + C53AA73242D70049D68DCA526B69D005 /* CompactMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompactMap.swift; path = RxSwift/Observables/CompactMap.swift; sourceTree = ""; }; + C57355D0496F6CA05BD3B095F859BF67 /* DispatchQueueConfiguration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DispatchQueueConfiguration.swift; path = RxSwift/Schedulers/Internal/DispatchQueueConfiguration.swift; sourceTree = ""; }; + C6CEDE2E14A6455694E1E27F4AC1DA6B /* Zip+arity.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Zip+arity.swift"; path = "RxSwift/Observables/Zip+arity.swift"; sourceTree = ""; }; + C7182CF8BE4608290699B6B2CF78E388 /* ObservableType+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+Extensions.swift"; path = "RxSwift/ObservableType+Extensions.swift"; sourceTree = ""; }; + C7FBC5DD60EF61D351B0CA282AA2987E /* Deferred.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Deferred.swift; path = RxSwift/Observables/Deferred.swift; sourceTree = ""; }; + C84F1DF9E3AB5F5CF0D39D814F75A4F5 /* RxTableViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDelegateProxy.swift; sourceTree = ""; }; + C89AAA90232D76CB06DD77296FE8745B /* Observable+Bind.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Observable+Bind.swift"; path = "RxCocoa/Common/Observable+Bind.swift"; sourceTree = ""; }; + C8E167AE7AF784540620A299389233DC /* OperationQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OperationQueueScheduler.swift; path = RxSwift/Schedulers/OperationQueueScheduler.swift; sourceTree = ""; }; + C9FF1808BD217AC51DBC0323F10A5641 /* Queue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = Platform/DataStructures/Queue.swift; sourceTree = ""; }; + CB2FCE9EFC6B4AF321E0972F36214AFF /* DisposeBag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBag.swift; path = RxSwift/Disposables/DisposeBag.swift; sourceTree = ""; }; + CC17AA237A1B658AD0238FD93F0DFD62 /* Completable+AndThen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Completable+AndThen.swift"; path = "RxSwift/Traits/PrimitiveSequence/Completable+AndThen.swift"; sourceTree = ""; }; + CD27C6BF074BBDBCC0E702778BA185B3 /* SubscriptionDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SubscriptionDisposable.swift; path = RxSwift/Disposables/SubscriptionDisposable.swift; sourceTree = ""; }; + CDF053478C3D4A12F08977D089A9185F /* ReplaySubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ReplaySubject.swift; path = RxSwift/Subjects/ReplaySubject.swift; sourceTree = ""; }; + CECE3D4B1535B76770B404D8B990A429 /* Alamofire-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Alamofire-umbrella.h"; sourceTree = ""; }; + CF049EA98E5F9EE116DCE3833B01E3A8 /* RxTableViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewReactiveArrayDataSource.swift; path = RxCocoa/iOS/DataSources/RxTableViewReactiveArrayDataSource.swift; sourceTree = ""; }; + D18BC0612ED16A755787EC28623BEA19 /* PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PrimitiveSequence.swift; path = RxSwift/Traits/PrimitiveSequence/PrimitiveSequence.swift; sourceTree = ""; }; + D23F046BFB31018CD45DF786AA3F3152 /* Materialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Materialize.swift; path = RxSwift/Observables/Materialize.swift; sourceTree = ""; }; + D27530937BD04E067916C314B8DA2210 /* Result+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Result+Alamofire.swift"; path = "Source/Result+Alamofire.swift"; sourceTree = ""; }; + D37F407A84623FAB151F7CA5CCE94054 /* AnonymousDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnonymousDisposable.swift; path = RxSwift/Disposables/AnonymousDisposable.swift; sourceTree = ""; }; D3FD861E2E0492AE9D462784FEC12739 /* Pods-Instagram-Clone.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-Instagram-Clone.modulemap"; sourceTree = ""; }; - D44CA33D5BC8739EC2CFFC5E68FD0A0E /* NSView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSView+Rx.swift"; path = "RxCocoa/macOS/NSView+Rx.swift"; sourceTree = ""; }; - D62955DED9E7D2A6A45F30BCF5C5A8EB /* _RXDelegateProxy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXDelegateProxy.h; path = RxCocoa/Runtime/include/_RXDelegateProxy.h; sourceTree = ""; }; - D83A8EA89291EB91728C988DC3AE885E /* RxTableViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxTableViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxTableViewDelegateProxy.swift; sourceTree = ""; }; - D8748A054157E6C52B89C50AB9294372 /* ObservableConvertibleType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObservableConvertibleType.swift; path = RxSwift/ObservableConvertibleType.swift; sourceTree = ""; }; - D88D012987C2AB388AE2C7B2EC57E9DC /* Bag.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bag.swift; path = Platform/DataStructures/Bag.swift; sourceTree = ""; }; - D8A9924027370221407B27E38E6125CB /* CurrentThreadScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CurrentThreadScheduler.swift; path = RxSwift/Schedulers/CurrentThreadScheduler.swift; sourceTree = ""; }; - D8AB807816C8B19247B4695711078D12 /* Date+Dispatch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Date+Dispatch.swift"; path = "RxSwift/Date+Dispatch.swift"; sourceTree = ""; }; - D8EB9624A417AD927C74289745F8DCAF /* Queue.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Queue.swift; path = Platform/DataStructures/Queue.swift; sourceTree = ""; }; - D8F036DCFF46DF69F13DA9E48C0B053C /* Scan.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Scan.swift; path = RxSwift/Observables/Scan.swift; sourceTree = ""; }; - D98877E126D60C268E5194134E3EC82A /* AddRef.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AddRef.swift; path = RxSwift/Observables/AddRef.swift; sourceTree = ""; }; - D99FF3EBFFA528FACCD94484CE9C3D8E /* BooleanDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BooleanDisposable.swift; path = RxSwift/Disposables/BooleanDisposable.swift; sourceTree = ""; }; - DBED721EBC4C0D72C86FCFB0430E6C7D /* Completable+AndThen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Completable+AndThen.swift"; path = "RxSwift/Traits/PrimitiveSequence/Completable+AndThen.swift"; sourceTree = ""; }; - DD02EB1D4A7B9800C069F8CD6EC1CB34 /* SchedulerType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SchedulerType.swift; path = RxSwift/SchedulerType.swift; sourceTree = ""; }; - DE05D49A0D640FFF40FF956D3870AE70 /* UIDatePicker+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIDatePicker+Rx.swift"; path = "RxCocoa/iOS/UIDatePicker+Rx.swift"; sourceTree = ""; }; - DE3973E65F651392AEF7DF2E8E748EA6 /* RxMutableBox.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxMutableBox.swift; path = RxSwift/RxMutableBox.swift; sourceTree = ""; }; - E09D984913B78C1ACC200E9E15BE4ED1 /* RxWKNavigationDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxWKNavigationDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxWKNavigationDelegateProxy.swift; sourceTree = ""; }; - E1D86B6152B2D9A5AD3AEBAD65A7FD53 /* KVORepresentable+Swift.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "KVORepresentable+Swift.swift"; path = "RxCocoa/Foundation/KVORepresentable+Swift.swift"; sourceTree = ""; }; - E40671A9B964030A4CE7429E95CDB983 /* Never.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Never.swift; path = RxSwift/Observables/Never.swift; sourceTree = ""; }; - E48B6ACD2E4F63EB00A01373EFC62314 /* URLSession+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "URLSession+Rx.swift"; path = "RxCocoa/Foundation/URLSession+Rx.swift"; sourceTree = ""; }; - E5104C7B97A69637D48E0917C458C948 /* NSObject+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx.swift"; path = "RxCocoa/Foundation/NSObject+Rx.swift"; sourceTree = ""; }; - E540F3DE703DD3BB653266C40509D28C /* SkipWhile.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipWhile.swift; path = RxSwift/Observables/SkipWhile.swift; sourceTree = ""; }; - E58AD4BEDFFAF702BDB724E21A684C6F /* RecursiveScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveScheduler.swift; path = RxSwift/Schedulers/RecursiveScheduler.swift; sourceTree = ""; }; - E6DDD5AE4C8E5CF9BFACA325BD81013C /* ObservableConvertibleType+Signal.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+Signal.swift"; path = "RxCocoa/Traits/Signal/ObservableConvertibleType+Signal.swift"; sourceTree = ""; }; - E80158E8E533E6E6412E82B0007A6D43 /* SynchronizedOnType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedOnType.swift; path = RxSwift/Concurrency/SynchronizedOnType.swift; sourceTree = ""; }; - EA7F5C6548DC2DC42FDA589FD0A2E46F /* HistoricalSchedulerTimeConverter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HistoricalSchedulerTimeConverter.swift; path = RxSwift/Schedulers/HistoricalSchedulerTimeConverter.swift; sourceTree = ""; }; - EAC5124547E5FFED02E336C7C60B257F /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Extensions.swift"; path = "Platform/DispatchQueue+Extensions.swift"; sourceTree = ""; }; - EACCE5DEA2BBD802FE23A452B0498E8F /* NSObject+Rx+KVORepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx+KVORepresentable.swift"; path = "RxCocoa/Foundation/NSObject+Rx+KVORepresentable.swift"; sourceTree = ""; }; - EAF8210EDCD60CEBB76BA4E5DD73C877 /* AsSingle.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsSingle.swift; path = RxSwift/Observables/AsSingle.swift; sourceTree = ""; }; - EB43DEDAB36933CD1961B889C31CEFDD /* BehaviorSubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BehaviorSubject.swift; path = RxSwift/Subjects/BehaviorSubject.swift; sourceTree = ""; }; - EBC4E4528155E113ADD9AACE99B80898 /* SkipUntil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipUntil.swift; path = RxSwift/Observables/SkipUntil.swift; sourceTree = ""; }; - EC1D1864465B4C3358F1536A4A8A44EA /* _RXObjCRuntime.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = _RXObjCRuntime.h; path = RxCocoa/Runtime/include/_RXObjCRuntime.h; sourceTree = ""; }; - ED8F0268E6C47E5861B76EA99770D8B7 /* Infallible+Create.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Infallible+Create.swift"; path = "RxSwift/Traits/Infallible/Infallible+Create.swift"; sourceTree = ""; }; - ED909CFE87DA665DEA46BF2B7B8CEA03 /* UISwitch+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISwitch+Rx.swift"; path = "RxCocoa/iOS/UISwitch+Rx.swift"; sourceTree = ""; }; - EE1B73E6DC096DBF6B3439E935446EB7 /* UIRefreshControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIRefreshControl+Rx.swift"; path = "RxCocoa/iOS/UIRefreshControl+Rx.swift"; sourceTree = ""; }; - EE5CAA2DF30E75CB6DBAE64575FAB211 /* ReplaySubject.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ReplaySubject.swift; path = RxSwift/Subjects/ReplaySubject.swift; sourceTree = ""; }; - EF1514228AEDC411709E7F1E8DD9A1A6 /* Utils.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = RxRelay/Utils.swift; sourceTree = ""; }; - F09AB9864E4B8FC8057599191A758CE3 /* DelegateProxyType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DelegateProxyType.swift; path = RxCocoa/Common/DelegateProxyType.swift; sourceTree = ""; }; - F12C996DEAA556F70B5F761B97AF62CE /* GroupBy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GroupBy.swift; path = RxSwift/Observables/GroupBy.swift; sourceTree = ""; }; - F136EE513E530DD4746D00FF450D357C /* DispatchQueueConfiguration.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DispatchQueueConfiguration.swift; path = RxSwift/Schedulers/Internal/DispatchQueueConfiguration.swift; sourceTree = ""; }; - F17362E34ACF3E2937AEF3326734AF9B /* OperationQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OperationQueueScheduler.swift; path = RxSwift/Schedulers/OperationQueueScheduler.swift; sourceTree = ""; }; - F34C096CAE0E50C543DD70356A57665F /* ReplayRelay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ReplayRelay.swift; path = RxRelay/ReplayRelay.swift; sourceTree = ""; }; - F498B2C52627D4B3747D8E8D2ED83E9D /* WithUnretained.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WithUnretained.swift; path = RxSwift/Observables/WithUnretained.swift; sourceTree = ""; }; - F5039A8657AC236E4C8277A1A9039360 /* InfiniteSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfiniteSequence.swift; path = Platform/DataStructures/InfiniteSequence.swift; sourceTree = ""; }; - F7F6E8678CF19A4F655E0533A1909983 /* ControlProperty+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ControlProperty+Driver.swift"; path = "RxCocoa/Traits/Driver/ControlProperty+Driver.swift"; sourceTree = ""; }; - FABADFC21256981C272E6D78A090EC30 /* Map.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Map.swift; path = RxSwift/Observables/Map.swift; sourceTree = ""; }; - FCA80E4EC28B8A2A8DA36ABC61F686AD /* Catch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Catch.swift; path = RxSwift/Observables/Catch.swift; sourceTree = ""; }; - FDD223851F1F5B630321574515DCFEC2 /* RxCocoa-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxCocoa-prefix.pch"; sourceTree = ""; }; - FF6D9B3D35590C7721824E06FC38BC7A /* Multicast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Multicast.swift; path = RxSwift/Observables/Multicast.swift; sourceTree = ""; }; + D4258692E67A0CB362F7BB3D91413B26 /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Extensions.swift"; path = "Platform/DispatchQueue+Extensions.swift"; sourceTree = ""; }; + D514C0BFAF080B34155E84CCBC3F2AD7 /* SerialDispatchQueueScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDispatchQueueScheduler.swift; path = RxSwift/Schedulers/SerialDispatchQueueScheduler.swift; sourceTree = ""; }; + D5F9933EF3E2D0E5C9A38450DA95C940 /* SingleAsync.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SingleAsync.swift; path = RxSwift/Observables/SingleAsync.swift; sourceTree = ""; }; + D658D77B0412C8504611038D50C9B8DC /* Enumerated.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Enumerated.swift; path = RxSwift/Observables/Enumerated.swift; sourceTree = ""; }; + D6D806B06479DC634E428071464C933F /* RxPickerViewDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxPickerViewDelegateProxy.swift; sourceTree = ""; }; + D7E8F79E7DC88DEB6DFACA82D883EE9E /* ObserverType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverType.swift; path = RxSwift/ObserverType.swift; sourceTree = ""; }; + D8096FEBA479025EB40840B0CC6BD31E /* NSTextStorage+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSTextStorage+Rx.swift"; path = "RxCocoa/iOS/NSTextStorage+Rx.swift"; sourceTree = ""; }; + D83242FBC909C2DC4C102061C1D985C7 /* RxSwift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "RxSwift-umbrella.h"; sourceTree = ""; }; + D86EDF0C7FC833194B4391F2E04A1DC8 /* _RX.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = _RX.m; path = RxCocoa/Runtime/_RX.m; sourceTree = ""; }; + D89AF9F1C03B2EA8FBCB02834E6E7DB9 /* ResponseSerialization.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ResponseSerialization.swift; path = Source/ResponseSerialization.swift; sourceTree = ""; }; + D913C2691FF84A8A5E872398995AC7F6 /* NSObject+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSObject+Rx.swift"; path = "RxCocoa/Foundation/NSObject+Rx.swift"; sourceTree = ""; }; + D946CD415A40593F4E87F434B15FBFB3 /* AsMaybe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AsMaybe.swift; path = RxSwift/Observables/AsMaybe.swift; sourceTree = ""; }; + D96A62187B1746415E8E24F1EC2EA0E4 /* UIBarButtonItem+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIBarButtonItem+Rx.swift"; path = "RxCocoa/iOS/UIBarButtonItem+Rx.swift"; sourceTree = ""; }; + DD704C7FD77889B382D1881BE82B57CA /* DisposeBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DisposeBase.swift; path = RxSwift/Disposables/DisposeBase.swift; sourceTree = ""; }; + DD75294A445E2D81BD626118984385FA /* BinaryDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BinaryDisposable.swift; path = RxSwift/Disposables/BinaryDisposable.swift; sourceTree = ""; }; + DD97EB9B9E811F96C7484EB462830C06 /* WithUnretained.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = WithUnretained.swift; path = RxSwift/Observables/WithUnretained.swift; sourceTree = ""; }; + DE088314501929D3EC446CF926925ACA /* RedirectHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RedirectHandler.swift; path = Source/RedirectHandler.swift; sourceTree = ""; }; + DECFD6204777ED86D3E84F3EFEAEE6C0 /* Dematerialize.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Dematerialize.swift; path = RxSwift/Observables/Dematerialize.swift; sourceTree = ""; }; + DED707571AA14733539CD9ED34AD9CD3 /* Response.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Response.swift; path = Source/Response.swift; sourceTree = ""; }; + DF920294818B5015C2A432741B8449ED /* RxCollectionViewReactiveArrayDataSource.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCollectionViewReactiveArrayDataSource.swift; path = RxCocoa/iOS/DataSources/RxCollectionViewReactiveArrayDataSource.swift; sourceTree = ""; }; + E1B5369C855073293C39F870980BA7DA /* UINavigationController+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UINavigationController+Rx.swift"; path = "RxCocoa/iOS/UINavigationController+Rx.swift"; sourceTree = ""; }; + E1BC592E13CDF07E2B7ECDFED477DC79 /* PublishRelay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PublishRelay.swift; path = RxRelay/PublishRelay.swift; sourceTree = ""; }; + E233119C4C85536D7158A45BC58EE2BC /* Timer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timer.swift; path = RxSwift/Observables/Timer.swift; sourceTree = ""; }; + E358CE05FC83CCB4181BCD48A6808920 /* DispatchQueue+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Alamofire.swift"; path = "Source/DispatchQueue+Alamofire.swift"; sourceTree = ""; }; + E43A403DE21567DCAB3F49FC518B26B9 /* RecursiveLock.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveLock.swift; path = Platform/RecursiveLock.swift; sourceTree = ""; }; + E4607B3ED8CFA90C52AF18FFA2661128 /* Concat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Concat.swift; path = RxSwift/Observables/Concat.swift; sourceTree = ""; }; + E4BF685D4B1DD3AC80C1A61C3A326CDD /* Switch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Switch.swift; path = RxSwift/Observables/Switch.swift; sourceTree = ""; }; + E5616C61981FF49AAC8EC1C8E02D6860 /* Buffer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Buffer.swift; path = RxSwift/Observables/Buffer.swift; sourceTree = ""; }; + E62DDC544E8AC865B9AA08706E6FC139 /* Request.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Request.swift; path = Source/Request.swift; sourceTree = ""; }; + E6F6DD6B4E80ED9DDB1730AB62B8CDBC /* OperationQueue+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "OperationQueue+Alamofire.swift"; path = "Source/OperationQueue+Alamofire.swift"; sourceTree = ""; }; + E95780524ED5621196640AB551C752A4 /* Zip.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Zip.swift; path = RxSwift/Observables/Zip.swift; sourceTree = ""; }; + E96DDF40C7F94101633F7E4244996BF6 /* Utils.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = RxRelay/Utils.swift; sourceTree = ""; }; + E98E87EE662818FA7ED50231400C4D27 /* Window.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Window.swift; path = RxSwift/Observables/Window.swift; sourceTree = ""; }; + E99C8AF3D55554B142A4F58C1CD027E4 /* ScheduledDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScheduledDisposable.swift; path = RxSwift/Disposables/ScheduledDisposable.swift; sourceTree = ""; }; + EA7D0DE84DEAC2C941CAF698E76580EB /* ReplayRelay.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ReplayRelay.swift; path = RxRelay/ReplayRelay.swift; sourceTree = ""; }; + EBDEC0F05CE0B5F1B79334BA357E6F76 /* RxCocoa.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxCocoa.swift; path = RxCocoa/RxCocoa.swift; sourceTree = ""; }; + EE5F5D65B6D06DECF5638D0B4908DC4F /* Repeat.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Repeat.swift; path = RxSwift/Observables/Repeat.swift; sourceTree = ""; }; + EF1E3D9A965EAC45B9F4E268B89C23F7 /* Catch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Catch.swift; path = RxSwift/Observables/Catch.swift; sourceTree = ""; }; + F0ABDFA66654E18EEE7E48DA5548533F /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = RxSwift/Errors.swift; sourceTree = ""; }; + F0FABE638332DAE9CB1544D1EADB9154 /* RxRelay.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = RxRelay.modulemap; sourceTree = ""; }; + F1013EB27F868D358C47ED382D6D4F89 /* Infallible+Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Infallible+Operators.swift"; path = "RxSwift/Traits/Infallible/Infallible+Operators.swift"; sourceTree = ""; }; + F1021DE272385518E83073F8F688559B /* ObservableConvertibleType+Driver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableConvertibleType+Driver.swift"; path = "RxCocoa/Traits/Driver/ObservableConvertibleType+Driver.swift"; sourceTree = ""; }; + F1505651CC182DC052570C0F0245D640 /* UIApplication+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIApplication+Rx.swift"; path = "RxCocoa/iOS/UIApplication+Rx.swift"; sourceTree = ""; }; + F153DE82AECB4A5F740D245E96EBFDBF /* SkipUntil.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SkipUntil.swift; path = RxSwift/Observables/SkipUntil.swift; sourceTree = ""; }; + F2B90B3B71B154BF22849D356E334730 /* SerialDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SerialDisposable.swift; path = RxSwift/Disposables/SerialDisposable.swift; sourceTree = ""; }; + F344AD341770313494511A6FC34CD7F9 /* AnyObserver.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnyObserver.swift; path = RxSwift/AnyObserver.swift; sourceTree = ""; }; + F4DBD5C098129C5A899245FCFCFE90F2 /* KVORepresentable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = KVORepresentable.swift; path = RxCocoa/Foundation/KVORepresentable.swift; sourceTree = ""; }; + F534EAD3C0BE78520779A2B1FA5E46B6 /* Platform.Linux.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.Linux.swift; path = Platform/Platform.Linux.swift; sourceTree = ""; }; + F56916BB23B56CC212997FCF13F2D6C3 /* Alamofire-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Alamofire-prefix.pch"; sourceTree = ""; }; + F577F1C935B3E560C16CE20C6521266B /* SynchronizedDisposeType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SynchronizedDisposeType.swift; path = RxSwift/Concurrency/SynchronizedDisposeType.swift; sourceTree = ""; }; + F65EFD9FCE2C86F5C16EF6707DAEE01A /* CachedResponseHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CachedResponseHandler.swift; path = Source/CachedResponseHandler.swift; sourceTree = ""; }; + F67F863AAD2C0C759AC4DCDA316297A5 /* Binder.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Binder.swift; path = RxSwift/Binder.swift; sourceTree = ""; }; + F708BA46014EA7CCCE42123E340788AB /* Empty.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Empty.swift; path = RxSwift/Observables/Empty.swift; sourceTree = ""; }; + F70ECF0CFF0163ADABFC3B6C7D328962 /* ShareReplayScope.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ShareReplayScope.swift; path = RxSwift/Observables/ShareReplayScope.swift; sourceTree = ""; }; + F747BF73A3B693E20F3184D9ED742B82 /* Signal+Subscription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Signal+Subscription.swift"; path = "RxCocoa/Traits/Signal/Signal+Subscription.swift"; sourceTree = ""; }; + F7E8ED230B0233D8CA891E48B052C4E8 /* RecursiveScheduler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecursiveScheduler.swift; path = RxSwift/Schedulers/RecursiveScheduler.swift; sourceTree = ""; }; + F7F31A302B3F3DC88ABBBAEBC47911DF /* ObservableType+PrimitiveSequence.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ObservableType+PrimitiveSequence.swift"; path = "RxSwift/Traits/PrimitiveSequence/ObservableType+PrimitiveSequence.swift"; sourceTree = ""; }; + F87BB95834BDD56A6F6615F57EA3B47D /* UIRefreshControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIRefreshControl+Rx.swift"; path = "RxCocoa/iOS/UIRefreshControl+Rx.swift"; sourceTree = ""; }; + F945667BC8F068155D11033D255A3993 /* CompositeDisposable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompositeDisposable.swift; path = RxSwift/Disposables/CompositeDisposable.swift; sourceTree = ""; }; + F9F6C121115219E23559F019FF606BCD /* VirtualTimeConverterType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VirtualTimeConverterType.swift; path = RxSwift/Schedulers/VirtualTimeConverterType.swift; sourceTree = ""; }; + FA094BCF75063D7C21A409A5551B01BE /* RxSearchControllerDelegateProxy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxSearchControllerDelegateProxy.swift; path = RxCocoa/iOS/Proxies/RxSearchControllerDelegateProxy.swift; sourceTree = ""; }; + FA1896E16598842002E1E264F719366E /* UIStepper+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIStepper+Rx.swift"; path = "RxCocoa/iOS/UIStepper+Rx.swift"; sourceTree = ""; }; + FBD714AA5F51DF464FA139BFF404A1F7 /* UISegmentedControl+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UISegmentedControl+Rx.swift"; path = "RxCocoa/iOS/UISegmentedControl+Rx.swift"; sourceTree = ""; }; + FC0D711F5C8019E955B578378608C5D1 /* TakeLast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TakeLast.swift; path = RxSwift/Observables/TakeLast.swift; sourceTree = ""; }; + FCF8D4F77B2D4B21FADE9F4BFA0F45B9 /* NSButton+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "NSButton+Rx.swift"; path = "RxCocoa/macOS/NSButton+Rx.swift"; sourceTree = ""; }; + FD0CE05D5D076B1B5190EE5DF97FD54E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + FD6A2B3CDA9EA6E76F57EDAB7349515F /* ObserverBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ObserverBase.swift; path = RxSwift/Observers/ObserverBase.swift; sourceTree = ""; }; + FD6E426F20C80EA25A69B8D17C2C9DFB /* RxRelay.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = RxRelay.release.xcconfig; sourceTree = ""; }; + FD7918FA9555E6D24F7C7C37B53D3FC5 /* RetryPolicy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RetryPolicy.swift; path = Source/RetryPolicy.swift; sourceTree = ""; }; + FD8B024487048CCF8C23000257E0FDDA /* UIPickerView+Rx.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIPickerView+Rx.swift"; path = "RxCocoa/iOS/UIPickerView+Rx.swift"; sourceTree = ""; }; FF8B264DFE802855D5D67E7CDDABFC3C /* RxRelay */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = RxRelay; path = RxRelay.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - FFE20639826F86C0A485DCE1783C3396 /* RxPickerViewAdapter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RxPickerViewAdapter.swift; path = RxCocoa/iOS/DataSources/RxPickerViewAdapter.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 0705890A408D203E7861663DF02E14CE /* Frameworks */ = { + 15DC142A7EE833251AA37FC8E2B8E01F /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - ACA0685005609FA22A3C7EB8C70EB94B /* Foundation.framework in Frameworks */, + 7B068137A8925891446203B5D3D6A4ED /* CFNetwork.framework in Frameworks */, + 0F4037DBF307AC8058BD0A3D35C7E7E9 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -685,141 +778,51 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 9EF7D08E3C67C1796D9410DF9F9AF313 /* Frameworks */ = { + 55DC75CEFCA651A08098DF1B82B0AF75 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2A6A7FA29F2A569A74F5DF329060C30A /* Foundation.framework in Frameworks */, + 29A045F0798283EAD8863A575B5A18FC /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; - E7C204DC6B7DEFD4553559C2C873AFD1 /* Frameworks */ = { + 6D1DDCBE282BCAF633EDA6632D43FD3C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 7394A3EA44F09919B4D5BE4C9F642AA0 /* Foundation.framework in Frameworks */, + 6B26A5BF0DAF24259CD2BBD52A8C936A /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 9C601D122E249EC454C0E310DE3026DD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DA736FAB25CE2D01EDB9B3196789B241 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 07386EB2A966C1599FAB9AC4171DFFE7 /* RxCocoa */ = { + 0C2CD72DB96BBF31047FE8A315A451C9 /* Products */ = { isa = PBXGroup; children = ( - BE780295A25F4BCABC879D1536A3C54E /* _RX.h */, - 3F03494C7F9242E59237EC6E7B3A8D6F /* _RX.m */, - D62955DED9E7D2A6A45F30BCF5C5A8EB /* _RXDelegateProxy.h */, - 4BAE0BC077E8C62320097689E54D211B /* _RXDelegateProxy.m */, - 5EC3A3C876BB6F997AA895DFC1E92134 /* _RXKVOObserver.h */, - 8A35B44531A4D80CEAB2B91D2C3B1F93 /* _RXKVOObserver.m */, - EC1D1864465B4C3358F1536A4A8A44EA /* _RXObjCRuntime.h */, - 01AB5F3B630755C56EC18F68BF4C67EC /* _RXObjCRuntime.m */, - D88D012987C2AB388AE2C7B2EC57E9DC /* Bag.swift */, - 610CD268ADB35154B7AA77C94FDFE206 /* BehaviorRelay+Driver.swift */, - 800125918B1A34EEA9B5EBF32842ADC6 /* ControlEvent.swift */, - BE159A12F2C43C59116A33FFB85E05D6 /* ControlEvent+Driver.swift */, - 791B8B0D9B49A4D288CFDE5AFAC9101F /* ControlEvent+Signal.swift */, - 3B6EF5FB2BA8D6F9CA45221D11FCBBA5 /* ControlProperty.swift */, - F7F6E8678CF19A4F655E0533A1909983 /* ControlProperty+Driver.swift */, - A175A343983FD9CE1E9FA110FB2F40D8 /* ControlTarget.swift */, - 1EE9FE35EE4E7109EA34CC2443F5C817 /* DelegateProxy.swift */, - F09AB9864E4B8FC8057599191A758CE3 /* DelegateProxyType.swift */, - EAC5124547E5FFED02E336C7C60B257F /* DispatchQueue+Extensions.swift */, - D174A224B1906B2C2C1AFC4A244D0D7E /* Driver.swift */, - 2B51F3BF99D9237CADBEED71883FFEA2 /* Driver+Subscription.swift */, - 562BCC9B350F163DACF15AA79D23DC08 /* Infallible+Bind.swift */, - 1640FC349F21362CD2F1E8C375FEB710 /* InfiniteSequence.swift */, - 4CE9F2DE870FB9EA5E6080F76C2DA110 /* ItemEvents.swift */, - 1699725A75E793AF47AFA08A03CAAFA5 /* KVORepresentable.swift */, - 359C8B4E3F1950C1B077B313A05E98AC /* KVORepresentable+CoreGraphics.swift */, - E1D86B6152B2D9A5AD3AEBAD65A7FD53 /* KVORepresentable+Swift.swift */, - 00644668DE9E29E96EA7D4E75CC41005 /* NotificationCenter+Rx.swift */, - 369E994557E0AC577044CE1CB58008D8 /* NSButton+Rx.swift */, - 5B9AAA50BFDD2E0E8D502F4ABE2600B8 /* NSControl+Rx.swift */, - E5104C7B97A69637D48E0917C458C948 /* NSObject+Rx.swift */, - EACCE5DEA2BBD802FE23A452B0498E8F /* NSObject+Rx+KVORepresentable.swift */, - 70A24B6007154434755D6FE7829B75E1 /* NSObject+Rx+RawRepresentable.swift */, - C4A85B1C742FF6712B8AB28B47273634 /* NSSlider+Rx.swift */, - 21ACAD4D869127D49821CD63EEE486D1 /* NSTextField+Rx.swift */, - C49739CC03AC63404753D77D10DED8B2 /* NSTextStorage+Rx.swift */, - ACB0E157337542EC91EA1D85D49A693E /* NSTextView+Rx.swift */, - D44CA33D5BC8739EC2CFFC5E68FD0A0E /* NSView+Rx.swift */, - 6878C434F38257C935BFBCB7DEB933CB /* Observable+Bind.swift */, - 640E4C77D7B6E46FC569C456AF6116A8 /* ObservableConvertibleType+Driver.swift */, - 499F02441FA51A23F940FA3843DF9A39 /* ObservableConvertibleType+SharedSequence.swift */, - E6DDD5AE4C8E5CF9BFACA325BD81013C /* ObservableConvertibleType+Signal.swift */, - 193BF64313DB29C3FCF62CB0CF3133BD /* Platform.Darwin.swift */, - 99D05E0077CF60BFE82F418F41B62749 /* Platform.Linux.swift */, - 0D864E28EC1869A5B35ECEDD2E5D8C68 /* PriorityQueue.swift */, - CD24ADA98445D4184D06F84FC41D11E7 /* PublishRelay+Signal.swift */, - D8EB9624A417AD927C74289745F8DCAF /* Queue.swift */, - A6FDDF83812BC79A312D7CCA6CD16F3A /* RecursiveLock.swift */, - 3F03CA510076C25FCD452E992F2EF3CA /* RxCocoa.h */, - BABD7A761EC023576B1B30D011691A99 /* RxCocoa.swift */, - 7D24118C234DAAA28D8D06D4DAED823B /* RxCocoaObjCRuntimeError+Extensions.swift */, - 4C4B4A36966A9C04C9538B5C5E2150C6 /* RxCocoaRuntime.h */, - 4D7E732DE2B0F4DDEEB2A48C3793EA57 /* RxCollectionViewDataSourcePrefetchingProxy.swift */, - 7F88262ECD3611A994C7578DF1AC90D3 /* RxCollectionViewDataSourceProxy.swift */, - 2DE36FB3974AF4A9D156AC0FAEFB182C /* RxCollectionViewDataSourceType.swift */, - 0B92717286BC70F18FCB3A9C3C72A5C6 /* RxCollectionViewDelegateProxy.swift */, - 007E7595BA898B76D1D326F44A95B104 /* RxCollectionViewReactiveArrayDataSource.swift */, - 5AF6C495B29F03325205155A225A54C3 /* RxNavigationControllerDelegateProxy.swift */, - FFE20639826F86C0A485DCE1783C3396 /* RxPickerViewAdapter.swift */, - B129863F6D3DDCF8834A7AA74F387E92 /* RxPickerViewDataSourceProxy.swift */, - 2235370476372BE73664E895A421D4FF /* RxPickerViewDataSourceType.swift */, - 4AE21CFC451474A9312ADDDF69FDB6D4 /* RxPickerViewDelegateProxy.swift */, - 97582CE90B36CC35E3344E0B3BB9E8C2 /* RxScrollViewDelegateProxy.swift */, - 0DC79611286237FB7BE7F29EDEB2421B /* RxSearchBarDelegateProxy.swift */, - 82BA61FA49C436947F13F9CE34C37C91 /* RxSearchControllerDelegateProxy.swift */, - CF7CFF4144277E2FAAAB06F989F256D1 /* RxTabBarControllerDelegateProxy.swift */, - A49C6178A71EBA0C7BE086BDE5ED1E66 /* RxTabBarDelegateProxy.swift */, - 27564198C961BEDCB7B0B8D2E04EE4B2 /* RxTableViewDataSourcePrefetchingProxy.swift */, - B9080BDB30A4F4776904377290A3551C /* RxTableViewDataSourceProxy.swift */, - B2825DBF5B8A8DF6608934526497046A /* RxTableViewDataSourceType.swift */, - D83A8EA89291EB91728C988DC3AE885E /* RxTableViewDelegateProxy.swift */, - 2E1283226017D88FCEDBE4D65F0E2E0B /* RxTableViewReactiveArrayDataSource.swift */, - 193EB48EF2C7E8AFF355077AEE6C05D3 /* RxTarget.swift */, - 70E0254E101D267C71ECFDB98B9CDD73 /* RxTextStorageDelegateProxy.swift */, - C1ED4EBF7B0699C1CE93E1628B4EA1B8 /* RxTextViewDelegateProxy.swift */, - E09D984913B78C1ACC200E9E15BE4ED1 /* RxWKNavigationDelegateProxy.swift */, - C37D5F564EE6CB890C291313BEE75AA2 /* SchedulerType+SharedSequence.swift */, - 22BD2B18828CB266956CE4D931265F42 /* SectionedViewDataSourceType.swift */, - 9B83A6E4784CADA73C8A18D843D3AA5E /* SharedSequence.swift */, - A6F2C49E08301D6E1CC8CAC4EB7B5905 /* SharedSequence+Operators.swift */, - 8403ABA7A5EF2EC532F05258F9862B4B /* SharedSequence+Operators+arity.swift */, - AA218DB75EBB15A3A1EF4327B71DC923 /* Signal.swift */, - AF22661CDDC03ED4086D034894D7C105 /* Signal+Subscription.swift */, - 2CC9D60AB695554951311124842EEABC /* TextInput.swift */, - 06BE21461C247B540A28540AD7B0C5F0 /* UIActivityIndicatorView+Rx.swift */, - 4F297B2AB79CC5002645FF512CDC17EB /* UIApplication+Rx.swift */, - 108B75EB704DE92E5D545B3BC0B813CD /* UIBarButtonItem+Rx.swift */, - 9D6DBC599BD63D72D8E840C6A338EFFE /* UIButton+Rx.swift */, - 944D4A34E4D244179DE134F59EFA997C /* UICollectionView+Rx.swift */, - D3A5DBD1144DF1DE9D79D0DE0FD9FF9C /* UIControl+Rx.swift */, - DE05D49A0D640FFF40FF956D3870AE70 /* UIDatePicker+Rx.swift */, - 0DFF0ABC6B463C32F017539E758D6582 /* UIGestureRecognizer+Rx.swift */, - 59CF1146BFFC0D96B3CC4F517DE8E4E1 /* UINavigationController+Rx.swift */, - 23CF8C2915AF525BE23908E7FE1610A5 /* UIPickerView+Rx.swift */, - EE1B73E6DC096DBF6B3439E935446EB7 /* UIRefreshControl+Rx.swift */, - 17385DE72069A424DE83D6B4072A92A5 /* UIScrollView+Rx.swift */, - B344BFC1C0D14E36B199F98E6172B040 /* UISearchBar+Rx.swift */, - C916D4DC300F09C2F9BA2F32539A274C /* UISearchController+Rx.swift */, - 777FFBD65C0FF1B4A48D8C459DC31721 /* UISegmentedControl+Rx.swift */, - 0775DFAAB9181064CDE9A004E96E7D3C /* UISlider+Rx.swift */, - 9D9880E80FCAA42588A804BA350064BE /* UIStepper+Rx.swift */, - ED909CFE87DA665DEA46BF2B7B8CEA03 /* UISwitch+Rx.swift */, - 94A493DBC8176AF0EE6C485A647C930F /* UITabBar+Rx.swift */, - 4A8BA0F62E7457838B8C4E134C2A48FF /* UITabBarController+Rx.swift */, - 9251013E40AF2901CABD2FC73CBE7614 /* UITableView+Rx.swift */, - B35CAAC7C2C89492E1A53DE25F9C8C35 /* UITextField+Rx.swift */, - BA422B8B653925DECD10A82F5864031D /* UITextView+Rx.swift */, - E48B6ACD2E4F63EB00A01373EFC62314 /* URLSession+Rx.swift */, - 9255CBB2D0BDBAB46779F2BE12C9834B /* WKWebView+Rx.swift */, - EDF7DABE160019C6A29E1438680F4A3B /* Support Files */, + 5D797E9A5C5782CE845840781FA1CC81 /* Alamofire */, + 8A126E0270200C843AF51E993B2E277F /* Pods-Instagram-Clone */, + BC432FD48A5932251F1CAFBC4BF74894 /* RxCocoa */, + FF8B264DFE802855D5D67E7CDDABFC3C /* RxRelay */, + 809C5FAB588354C9BA37DC3EAB8CB45C /* RxSwift */, ); - name = RxCocoa; - path = RxCocoa; + name = Products; + sourceTree = ""; + }; + 1628BF05B4CAFDCC3549A101F5A10A17 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 61C8CC330A5CA84DA2F5F1D32AB07069 /* iOS */, + ); + name = Frameworks; sourceTree = ""; }; 3B9BF16DAAF6E1C0C08C92C267C0AB7A /* Pods-Instagram-Clone */ = { @@ -847,310 +850,463 @@ name = "Targets Support Files"; sourceTree = ""; }; - 578452D2E740E91742655AC8F1636D1F /* iOS */ = { + 5351D47E9412153B50EB52369B9299C0 /* RxCocoa */ = { isa = PBXGroup; children = ( - 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */, + 057F21FAE790F4DD0A18A93296D0A71E /* _RX.h */, + D86EDF0C7FC833194B4391F2E04A1DC8 /* _RX.m */, + A82B59C46A8891A0AF7A544DDCDBE7A4 /* _RXDelegateProxy.h */, + 71C3768A32C06D82A80CB88CF8751FFB /* _RXDelegateProxy.m */, + 669DDE6F99F9C873BE8B242EBA224C37 /* _RXKVOObserver.h */, + 94E20CB67BEF87997F5C88B67D4165B1 /* _RXKVOObserver.m */, + 0143446C5F00E24690553D7E4A4EF54C /* _RXObjCRuntime.h */, + 0F365E68BF9F85C934803EEE843C7507 /* _RXObjCRuntime.m */, + 2D1F2097634F4C613AD8BAAD0128C338 /* Bag.swift */, + 7A3DD3E4A9A4673B47D4C6BB1ECC2FE8 /* BehaviorRelay+Driver.swift */, + B2798ACEB5A9F3BB777E6E657288583C /* ControlEvent.swift */, + 519B6C10B0C5FCC12A649E8403532674 /* ControlEvent+Driver.swift */, + 7887DA93F3CD7EF16FBDAF60F9A0C6A7 /* ControlEvent+Signal.swift */, + 5296303E7B76C7C449D2CC7E0E000281 /* ControlProperty.swift */, + 6A75C1BA7C53C89CFEF1F83EE37E7EE6 /* ControlProperty+Driver.swift */, + 4D8E35604B9593285F8880155599FE4F /* ControlTarget.swift */, + 237C88B64E2FC4D82877BD5916785674 /* DelegateProxy.swift */, + 95499D30AF1F2DE7A7CEA8AA0DBB0B3C /* DelegateProxyType.swift */, + D4258692E67A0CB362F7BB3D91413B26 /* DispatchQueue+Extensions.swift */, + 623EBC29B18495CA0C436D827CEE6728 /* Driver.swift */, + 0E3AEF057D82E1811AD90C4DE2267A79 /* Driver+Subscription.swift */, + 77B8D452A0987A391C116266CC693A6F /* Infallible+Bind.swift */, + 64A208A052C3CE6C1240B092E490CAB1 /* InfiniteSequence.swift */, + C26A34586BB25C239B0C93295410D6B7 /* ItemEvents.swift */, + F4DBD5C098129C5A899245FCFCFE90F2 /* KVORepresentable.swift */, + B0C41ED95427AF71D36B4F084BE5A6AE /* KVORepresentable+CoreGraphics.swift */, + 0D1078A15FDA40825DA0C34D1DCD56C0 /* KVORepresentable+Swift.swift */, + 1EE8D25372CE963CE58F7C2F4FB187CF /* NotificationCenter+Rx.swift */, + FCF8D4F77B2D4B21FADE9F4BFA0F45B9 /* NSButton+Rx.swift */, + 31FC37E7C3FDBAA92A3B8F8C6E840F31 /* NSControl+Rx.swift */, + D913C2691FF84A8A5E872398995AC7F6 /* NSObject+Rx.swift */, + 17E9145798CDAECA8E6048A90E9D4748 /* NSObject+Rx+KVORepresentable.swift */, + B417BFB59BD825253EAED7DD8806D519 /* NSObject+Rx+RawRepresentable.swift */, + 012453260A0F0691E70C3944FFAF048C /* NSSlider+Rx.swift */, + B82686D2BD45E21F1DB076390F8B0F25 /* NSTextField+Rx.swift */, + D8096FEBA479025EB40840B0CC6BD31E /* NSTextStorage+Rx.swift */, + B2AB38E402838475B1BDA2DE7834D96B /* NSTextView+Rx.swift */, + AAD641B0D7B200397821BB739A168DD1 /* NSView+Rx.swift */, + C89AAA90232D76CB06DD77296FE8745B /* Observable+Bind.swift */, + F1021DE272385518E83073F8F688559B /* ObservableConvertibleType+Driver.swift */, + 8F188F3631ABA83DC4520B28431AF8E1 /* ObservableConvertibleType+SharedSequence.swift */, + 11D4AFEAB2754F664EEDD11730507922 /* ObservableConvertibleType+Signal.swift */, + 8105F1AED97EBB31E9ECE90220331050 /* Platform.Darwin.swift */, + F534EAD3C0BE78520779A2B1FA5E46B6 /* Platform.Linux.swift */, + AB37CF81A092A3E976BE535DB38A6964 /* PriorityQueue.swift */, + B476816821E0315922ED7A6B7540AFB3 /* PublishRelay+Signal.swift */, + C9FF1808BD217AC51DBC0323F10A5641 /* Queue.swift */, + 953C63177619AB342C34EEE783C81EF8 /* RecursiveLock.swift */, + B961666FBD681C6B13B784C18D575465 /* RxCocoa.h */, + EBDEC0F05CE0B5F1B79334BA357E6F76 /* RxCocoa.swift */, + 1975EBAF55544BC70D2D790712F088CF /* RxCocoaObjCRuntimeError+Extensions.swift */, + 252782DAFEE92AF927AF401D81DC4756 /* RxCocoaRuntime.h */, + 56BCC58210173BBB48CBEEEA55B9A8AC /* RxCollectionViewDataSourcePrefetchingProxy.swift */, + 732036B3E5DD047637BB1B9A777EA1E5 /* RxCollectionViewDataSourceProxy.swift */, + 970FA5A266DB2924BBD2B982F74412EA /* RxCollectionViewDataSourceType.swift */, + 0B286A5673B1B7539EAE7FB20F57F746 /* RxCollectionViewDelegateProxy.swift */, + DF920294818B5015C2A432741B8449ED /* RxCollectionViewReactiveArrayDataSource.swift */, + 2CCCF0F617B295E0168704E10183E07A /* RxNavigationControllerDelegateProxy.swift */, + 41A8370357890336F08FB952BD79117F /* RxPickerViewAdapter.swift */, + 256B92342A5164F30F9289C7D50E5A6C /* RxPickerViewDataSourceProxy.swift */, + 63E36BC902C9ADA7FE3C6397491B5082 /* RxPickerViewDataSourceType.swift */, + D6D806B06479DC634E428071464C933F /* RxPickerViewDelegateProxy.swift */, + 470212E66C74D5757E37A837E2B1F0FD /* RxScrollViewDelegateProxy.swift */, + 6DBDD4E2905AB157F4C1B0DDC9AC1A2E /* RxSearchBarDelegateProxy.swift */, + FA094BCF75063D7C21A409A5551B01BE /* RxSearchControllerDelegateProxy.swift */, + 366AB29585827B22DA277DCC64C6210D /* RxTabBarControllerDelegateProxy.swift */, + 6591215365055B0134F330A97A10C301 /* RxTabBarDelegateProxy.swift */, + 11AF7CE62967AC244F55DA9E1BB1811B /* RxTableViewDataSourcePrefetchingProxy.swift */, + 4A218B60A6F3B33C317DFF65DD678205 /* RxTableViewDataSourceProxy.swift */, + 8F4EC36A54010622D3E1DBAF1CE07365 /* RxTableViewDataSourceType.swift */, + C84F1DF9E3AB5F5CF0D39D814F75A4F5 /* RxTableViewDelegateProxy.swift */, + CF049EA98E5F9EE116DCE3833B01E3A8 /* RxTableViewReactiveArrayDataSource.swift */, + 768133F2C2CC8674F7220CD20CBC738C /* RxTarget.swift */, + 91CA9BD79C42A139D0C8431BDFDA3223 /* RxTextStorageDelegateProxy.swift */, + 171C5F87CB9880D7A87F28226F3A2966 /* RxTextViewDelegateProxy.swift */, + 004BA208237B4E16EA699ACADC85AFE0 /* RxWKNavigationDelegateProxy.swift */, + A97D6619DD182B507FB857AD61304B44 /* SchedulerType+SharedSequence.swift */, + 12427AF8DF82101B9D78DAB0E6F28AAA /* SectionedViewDataSourceType.swift */, + 3049D7F3DC3CF301B6D08F7BBCF9930B /* SharedSequence.swift */, + 011C15D0AD92913A044FD01816592922 /* SharedSequence+Operators.swift */, + 844031D7991F5389D65BF8E22D318F9D /* SharedSequence+Operators+arity.swift */, + 4C233162E224D042B1A9ADB5FFC75596 /* Signal.swift */, + F747BF73A3B693E20F3184D9ED742B82 /* Signal+Subscription.swift */, + B766558A6AFFF5D989A09741CD470BA7 /* TextInput.swift */, + 3C193EEDF6B5EBAB9D21CA69760F3160 /* UIActivityIndicatorView+Rx.swift */, + F1505651CC182DC052570C0F0245D640 /* UIApplication+Rx.swift */, + D96A62187B1746415E8E24F1EC2EA0E4 /* UIBarButtonItem+Rx.swift */, + 0804998A043E63BCF0404A778DEE29D8 /* UIButton+Rx.swift */, + 83EE95F979FACA89F44D68CC3489DE8F /* UICollectionView+Rx.swift */, + 0755115E5EB323278C37AC66CAAE2B1A /* UIControl+Rx.swift */, + BDED6E55DC07C9A13486397B32A789B8 /* UIDatePicker+Rx.swift */, + 89EACE9FD0C33F1B6B27CC836BDBE706 /* UIGestureRecognizer+Rx.swift */, + E1B5369C855073293C39F870980BA7DA /* UINavigationController+Rx.swift */, + FD8B024487048CCF8C23000257E0FDDA /* UIPickerView+Rx.swift */, + F87BB95834BDD56A6F6615F57EA3B47D /* UIRefreshControl+Rx.swift */, + 44B8E99A079E190217E678B7AAFC79DA /* UIScrollView+Rx.swift */, + C181BCCEF5CFDF4873D117F1CE6E1BA4 /* UISearchBar+Rx.swift */, + A18BC45336950B8C433FD02E847AD38F /* UISearchController+Rx.swift */, + FBD714AA5F51DF464FA139BFF404A1F7 /* UISegmentedControl+Rx.swift */, + 6BC23ED6D414C352E57C88DC42A6022F /* UISlider+Rx.swift */, + FA1896E16598842002E1E264F719366E /* UIStepper+Rx.swift */, + C41B899C63FF345426E1B52A8A627AF6 /* UISwitch+Rx.swift */, + 510F8AF367E03012DF0695088BD61156 /* UITabBar+Rx.swift */, + C184367820F49866C61F406AD3D62154 /* UITabBarController+Rx.swift */, + 6AC71F58A210A9BF7B75395A077BCF53 /* UITableView+Rx.swift */, + 26C3823CD02898688DB8C4C27D6F1450 /* UITextField+Rx.swift */, + B958A400ABDE65E1B6A2F557B519841D /* UITextView+Rx.swift */, + 86E5EFE7C6AF249A0542C9D41215F5FE /* URLSession+Rx.swift */, + 011724A1A671D7E12ABD37BC873AE4BA /* WKWebView+Rx.swift */, + 70C5A402E7BD4875154FD33F8E88E88A /* Support Files */, ); - name = iOS; + name = RxCocoa; + path = RxCocoa; sourceTree = ""; }; - 5EF9B030B61E8FA79333F0B2AFA34E83 /* SwiftLint */ = { + 5F0D48E69705E7F4F650884B7218A0C3 /* Pods */ = { isa = PBXGroup; children = ( - C458C4025B7498BC6B0A79D88FDF1AE9 /* Support Files */, + D093A27314299CF82C3757198933365E /* Alamofire */, + 5351D47E9412153B50EB52369B9299C0 /* RxCocoa */, + E78FFAFA9DCC7AFA082533F2102E92D3 /* RxRelay */, + 79441F5504271AB6A89ABE42BD0982F4 /* RxSwift */, + 9CD96962E033D1330F3B3D5E4AE72F4C /* SwiftLint */, ); - name = SwiftLint; - path = SwiftLint; + name = Pods; sourceTree = ""; }; - 6B1253F8CFA6DBDFFACAB36671168BCF /* RxSwift */ = { + 61C8CC330A5CA84DA2F5F1D32AB07069 /* iOS */ = { isa = PBXGroup; children = ( - D98877E126D60C268E5194134E3EC82A /* AddRef.swift */, - 69FE9077C79452DD8408F90206503B5D /* Amb.swift */, - 75BD1907BE8577B050A2AD8FA2FA7B75 /* AnonymousDisposable.swift */, - A3399CFBB1396ACD6286EBA4D81D4D0C /* AnonymousObserver.swift */, - 87911FA9E065451BD946DC5DF3C59D3C /* AnyObserver.swift */, - 9584F2AD1F12E0E0F15B714F0CC6E68F /* AsMaybe.swift */, - EAF8210EDCD60CEBB76BA4E5DD73C877 /* AsSingle.swift */, - 52E585039525D24078FD09A43C1FB4E2 /* AsyncLock.swift */, - A9E3A902E1F2FE5A95218F7934C84C30 /* AsyncSubject.swift */, - 5574A45114B7AF48A6DE11C97987BFB6 /* AtomicInt.swift */, - 299E7425E04B095442F4A077219619DB /* Bag.swift */, - 6788801F19DA52CA8EE23A3201EFCF2F /* Bag+Rx.swift */, - EB43DEDAB36933CD1961B889C31CEFDD /* BehaviorSubject.swift */, - 8892F4474BA4B9852E09846DC7B861F0 /* BinaryDisposable.swift */, - 570D56F0F47A06EF81090D3C20ACC26C /* Binder.swift */, - D99FF3EBFFA528FACCD94484CE9C3D8E /* BooleanDisposable.swift */, - 47C9C5568753DC4ABA0764707F468FD3 /* Buffer.swift */, - 01B16DD2C82C26A727CDA0218AF2FB6D /* Cancelable.swift */, - FCA80E4EC28B8A2A8DA36ABC61F686AD /* Catch.swift */, - 3E452B621A51772D2378F31494E12D32 /* CombineLatest.swift */, - 3532C567B8EB7BAB306DDA6CA277B84D /* CombineLatest+arity.swift */, - 767BA97D4F49BFF48996CDFDCEDCAAF5 /* CombineLatest+Collection.swift */, - 08B063219062CCBA4FC87611947A024D /* CompactMap.swift */, - 2D9539B4F49FEE65309ABE756D3F4786 /* Completable.swift */, - DBED721EBC4C0D72C86FCFB0430E6C7D /* Completable+AndThen.swift */, - C255FF4F123BF4ECE7E8A1C5821F51FF /* CompositeDisposable.swift */, - 383C2AC03F6C6BD740AEDB5F72435FBB /* Concat.swift */, - A8C4AF57E2F918529D2AF398E1E5CDFB /* ConcurrentDispatchQueueScheduler.swift */, - 5F9CFCE6985273F3DE45053967790C1D /* ConcurrentMainScheduler.swift */, - 3FB3DECF9FA15E273D3F48AA2E9AEAB7 /* ConnectableObservableType.swift */, - 55502E9CDD82DB3C088023E52EF29CAF /* Create.swift */, - D8A9924027370221407B27E38E6125CB /* CurrentThreadScheduler.swift */, - D8AB807816C8B19247B4695711078D12 /* Date+Dispatch.swift */, - 5AC87BA30AF3E7421DB0DD8D9A73F869 /* Debounce.swift */, - AD8DB1146C2FD3850E2DC90065612219 /* Debug.swift */, - 61D33EF3A2C81402ABFD71409496E49F /* Decode.swift */, - 761783ACC956844B0C427D1A56C4050C /* DefaultIfEmpty.swift */, - 546E57E00BC246C6761986A013FB0DCA /* Deferred.swift */, - 544B2D6150A77A085C21CB5926471FE1 /* Delay.swift */, - 0517049528AB1D57EE93B9528EFC5077 /* DelaySubscription.swift */, - 62B3C64FFDCF5AF4054FD532B041ED61 /* Dematerialize.swift */, - 8DE31BF75E95FE12CF6EB3E9941E03E7 /* DispatchQueue+Extensions.swift */, - F136EE513E530DD4746D00FF450D357C /* DispatchQueueConfiguration.swift */, - 90BFC489D14E1BB573EDC77B78300C58 /* Disposable.swift */, - AC6807AD4C1E67D2C647316CD0ACFE54 /* Disposables.swift */, - C66DA023B9D646DC6A225AB65C154D7B /* DisposeBag.swift */, - 935118C1700F1FBAF0850D84AC0BF44A /* DisposeBase.swift */, - 26410040C396641DC2A2ABA618935E26 /* DistinctUntilChanged.swift */, - B2B24E3FC4E0E31678BE3D07FE5B5546 /* Do.swift */, - 404475EF1E226D1D3703A1AA7D0F355F /* ElementAt.swift */, - 74B7F67BA3B530028F633568D0A7D4CA /* Empty.swift */, - 69C99F11DF4D911FF5F58FF99637AEA8 /* Enumerated.swift */, - 52D7FC2FBFC96464543FC2D5284CC469 /* Error.swift */, - BD83661C7D461B34B59CBA67D428938E /* Errors.swift */, - 2CE52486EB2B3A9A3A429A00A5754CA9 /* Event.swift */, - 7889CA4E7E7326754FE945E78B60B4B1 /* Filter.swift */, - 8A0B47045699682A1F80DB7EC82EF7EC /* First.swift */, - 767D94760D69C37D5D5D80715BD2399E /* Generate.swift */, - F12C996DEAA556F70B5F761B97AF62CE /* GroupBy.swift */, - 9F09AB4C59893AD412B9A8974A44EFAF /* GroupedObservable.swift */, - 1C55F92F39ECE075EE04F1D61EFC0326 /* HistoricalScheduler.swift */, - EA7F5C6548DC2DC42FDA589FD0A2E46F /* HistoricalSchedulerTimeConverter.swift */, - 9D0818786883B7E84DC3216C80C0F342 /* ImmediateSchedulerType.swift */, - 8CA2662060A6EFE096AA3BB117ABF465 /* Infallible.swift */, - 6A570E94AC7743F742308E9408C3DEE9 /* Infallible+CombineLatest+arity.swift */, - ED8F0268E6C47E5861B76EA99770D8B7 /* Infallible+Create.swift */, - 7D8C3064DA8BE2AD59875B2AA63F7D8A /* Infallible+Operators.swift */, - 628BA9925CB8D093E9B8045E627C5FD3 /* Infallible+Zip+arity.swift */, - F5039A8657AC236E4C8277A1A9039360 /* InfiniteSequence.swift */, - 95A778976F3DF4C3E0BE8CFF8FFA3DCE /* InvocableScheduledItem.swift */, - 7DF318A6380B535D896F263A1D31A886 /* InvocableType.swift */, - 2BC86CE63EC0703205D3A01D0D570F08 /* Just.swift */, - 92A7E4BD7E45FB638F049D2CF3272D20 /* Lock.swift */, - 97A6F4201F3E82652819407100545509 /* LockOwnerType.swift */, - 5AC378ACD31FBB65065DB9EEDE4599CA /* MainScheduler.swift */, - FABADFC21256981C272E6D78A090EC30 /* Map.swift */, - 9D7F8F13AF4282C1D19D4B2E42A5FDE3 /* Materialize.swift */, - 0D63B0B75043E16A5215A4ECA19471EC /* Maybe.swift */, - D2C66B37865A7C240E9B137458195DBA /* Merge.swift */, - FF6D9B3D35590C7721824E06FC38BC7A /* Multicast.swift */, - E40671A9B964030A4CE7429E95CDB983 /* Never.swift */, - C591B3A68D801DC242DC1D3987FEE92F /* NopDisposable.swift */, - 70664A49465BD35C219845778B09404D /* Observable.swift */, - D8748A054157E6C52B89C50AB9294372 /* ObservableConvertibleType.swift */, - 60D291EF382DFED378C9057592F06218 /* ObservableConvertibleType+Infallible.swift */, - B30D4AF1264D8B0677474E3A66F22172 /* ObservableType.swift */, - 6943A86D4C4C86816F275975A3F56777 /* ObservableType+Extensions.swift */, - B1D7D698F8E89D6A74D2068A57CD9019 /* ObservableType+PrimitiveSequence.swift */, - 9F533CB02A453B09B128C0121F309F99 /* ObserveOn.swift */, - BF284C36287FCF12DED05CABACB2BA82 /* ObserverBase.swift */, - D3A723B60F3BBCF212075132049E83DF /* ObserverType.swift */, - F17362E34ACF3E2937AEF3326734AF9B /* OperationQueueScheduler.swift */, - B09EC6A25D0F81AE425C42CE3E04DF34 /* Optional.swift */, - B40E371D7A6BBFB7E8FE61981378D673 /* Platform.Darwin.swift */, - 09783CE839BFEBF2D75D0FDCD24233B5 /* Platform.Linux.swift */, - 265DFB94C2AE7AC0DC8CB4C276047CB6 /* PrimitiveSequence.swift */, - B810010130BCEDC6EFDBEFAA3F5E138F /* PrimitiveSequence+Zip+arity.swift */, - 2B91A7A9E5D728BE812EADFF1C66A76E /* PriorityQueue.swift */, - A9D4D718EE79B06EF7DA68A039598B40 /* Producer.swift */, - 619F731B252F401E63D0C2EE802F83C5 /* PublishSubject.swift */, - A7CF4533A429B848A2569FE826DFC277 /* Queue.swift */, - 285F374E9AFE8CE7A829816006FDEF7B /* Range.swift */, - A0A7DD927A1CA40ACB4A31136448C7B6 /* Reactive.swift */, - C26426EBCCB55CA8014D9D34B51CFE06 /* RecursiveLock.swift */, - E58AD4BEDFFAF702BDB724E21A684C6F /* RecursiveScheduler.swift */, - 72046CC8FB967C35B5E0DC3F870678A7 /* Reduce.swift */, - 5232F0716373C6707AA30C634546FCAE /* RefCountDisposable.swift */, - 089965FFF10BAC759D5721DA13057A92 /* Repeat.swift */, - EE5CAA2DF30E75CB6DBAE64575FAB211 /* ReplaySubject.swift */, - 04344BD8BBAE6840F81D834C19D77C19 /* RetryWhen.swift */, - 2F114313913428BF0B3DF63F4A9D3128 /* Rx.swift */, - DE3973E65F651392AEF7DF2E8E748EA6 /* RxMutableBox.swift */, - 3E69A66DD64CE026C3088FCE23AC5A8D /* Sample.swift */, - D8F036DCFF46DF69F13DA9E48C0B053C /* Scan.swift */, - CE7897050459FE64BF884DD0F493CCD2 /* ScheduledDisposable.swift */, - 508A20901B2C356FEAAF7D14031050F6 /* ScheduledItem.swift */, - 3BE14BF9AF5DB36145DD2FF859822332 /* ScheduledItemType.swift */, - 32B14FB3822E731DB6D717BCE0D19DEE /* SchedulerServices+Emulation.swift */, - DD02EB1D4A7B9800C069F8CD6EC1CB34 /* SchedulerType.swift */, - 9EAF3426B2E09A3FD26E570F5435C1C4 /* Sequence.swift */, - C350F7C7118DA156B0CBF3C4725BB1E2 /* SerialDispatchQueueScheduler.swift */, - 8A4ABC1DD59390FF09893BFC0EDECA6C /* SerialDisposable.swift */, - 96F124CB1F0EEFE46E9400A8A5A771D5 /* ShareReplayScope.swift */, - 7561914E2B359EE2F9867B879662FDBE /* Single.swift */, - 4670F49FCE04BE2C9B9127D7C02F25CB /* SingleAssignmentDisposable.swift */, - 2E04188FA34CE390796D91FF5E2B8886 /* SingleAsync.swift */, - 06AA9C625F3E30335B298A5366E2682C /* Sink.swift */, - 90009E81E181BC430376EC477FF1561B /* Skip.swift */, - EBC4E4528155E113ADD9AACE99B80898 /* SkipUntil.swift */, - E540F3DE703DD3BB653266C40509D28C /* SkipWhile.swift */, - 92E5B6359027EBC6DEC81A16B89FBBAB /* StartWith.swift */, - 5034BAB8BD865EB2CEB711500C270EB8 /* SubjectType.swift */, - 149172E51A3A87DAF5B5A38EF9199C6D /* SubscribeOn.swift */, - 253971F450F05D5006DDD0D919450D87 /* SubscriptionDisposable.swift */, - 40661C9CD5EA78C14FF62DF719B11B18 /* SwiftSupport.swift */, - B3E1DA0ABC944D798284B02ACCA2ACFA /* Switch.swift */, - 9044811BD3FCD91090DAAB658671FE6A /* SwitchIfEmpty.swift */, - 63C78B0D2870B348AB740CEAA27C2E74 /* SynchronizedDisposeType.swift */, - E80158E8E533E6E6412E82B0007A6D43 /* SynchronizedOnType.swift */, - 80F107C23AD0B22789290606EDE7C423 /* SynchronizedUnsubscribeType.swift */, - 898AC549FA3207BF3C86263F8BEC9241 /* TailRecursiveSink.swift */, - 338E26527677E48EDF3516E1ADA885D0 /* Take.swift */, - 523F251A7D75246E6AEF64CEE3209F7A /* TakeLast.swift */, - B1ED315F78613719616BD46F58A69425 /* TakeWithPredicate.swift */, - 7608E2D33CF20C31B9FA50AF57E5FDF9 /* Throttle.swift */, - 1BCC3DE64EB6BD619B9D9CF5F8E5F1F9 /* Timeout.swift */, - 15299F3579C722B10ACF13813B53ABCA /* Timer.swift */, - 3D10FE0979AA30BC837E8945BE181EAC /* ToArray.swift */, - 0EF1EEEFAE14249E6C2D2565A94EEA04 /* Using.swift */, - 4D6F74828D23AA06327E94D4B11F0483 /* VirtualTimeConverterType.swift */, - 18B3621E91765CDCDD2F0E491A5418EE /* VirtualTimeScheduler.swift */, - 0C7C50211D78C2371DED7C720B94CFEF /* Window.swift */, - 28A63C60790F5C7200738F8A762FE5B9 /* WithLatestFrom.swift */, - F498B2C52627D4B3747D8E8D2ED83E9D /* WithUnretained.swift */, - 431ED4903DBAE9C89C9C0473B2E0E298 /* Zip.swift */, - BD16B00CC1673ECEB6115FAC902E0B56 /* Zip+arity.swift */, - 2385E1134EA158765A41A546E3AE33BC /* Zip+Collection.swift */, - 775EE008D41685F9A26EE15796A31A28 /* Support Files */, + 8D3D57353834825F7B52B816066B7789 /* CFNetwork.framework */, + FD0CE05D5D076B1B5190EE5DF97FD54E /* Foundation.framework */, ); - name = RxSwift; - path = RxSwift; + name = iOS; sourceTree = ""; }; - 775EE008D41685F9A26EE15796A31A28 /* Support Files */ = { + 70C5A402E7BD4875154FD33F8E88E88A /* Support Files */ = { isa = PBXGroup; children = ( - 14EBA27517C50FBCE1EA2A7A2A459843 /* RxSwift.modulemap */, - D2C1D6D0DAE2CE5850872E7FC3538FCF /* RxSwift-dummy.m */, - 1D7D582FFA9DDD192BBDF4FABA8D16D7 /* RxSwift-Info.plist */, - 3419D41B8498B933438FAFDA15054252 /* RxSwift-prefix.pch */, - CFBE22268708B2C3228C3D3C3F89C570 /* RxSwift-umbrella.h */, - AF77625DB712A38BD99168A49606C55F /* RxSwift.debug.xcconfig */, - 9E98442EE02EEDF78B15D2F6A5168DDA /* RxSwift.release.xcconfig */, + ADFAD819AD24E96A15E4C119C4BDFE0C /* RxCocoa.modulemap */, + 5F538C639AC1945189EB1CE26FAC6BEF /* RxCocoa-dummy.m */, + A0EB2A699BBE7A22239A58AD031BB825 /* RxCocoa-Info.plist */, + 1AE2C2EADA7F5DB06B8F3226F9EA5B97 /* RxCocoa-prefix.pch */, + 93DB2AFE7188A1E1A53B376DF03ED898 /* RxCocoa-umbrella.h */, + 5B6CB2FCC481D092A24CD0A922397325 /* RxCocoa.debug.xcconfig */, + 89DE6A4A58CC9CBDADB822DD004594A0 /* RxCocoa.release.xcconfig */, ); name = "Support Files"; - path = "../Target Support Files/RxSwift"; + path = "../Target Support Files/RxCocoa"; sourceTree = ""; }; - 7EA5F21C185E2FBACE494BCD6621C8CE /* Pods */ = { + 71054607DCDF5FA0EE1ABF0297462930 /* Support Files */ = { isa = PBXGroup; children = ( - 07386EB2A966C1599FAB9AC4171DFFE7 /* RxCocoa */, - 886CED194CCA041E7E84D0BB03B1176D /* RxRelay */, - 6B1253F8CFA6DBDFFACAB36671168BCF /* RxSwift */, - 5EF9B030B61E8FA79333F0B2AFA34E83 /* SwiftLint */, + 9CC6DB2A76E65928E8309796E3B4EC66 /* RxSwift.modulemap */, + B5B304BD966D13EF655D5CC30AF30CB3 /* RxSwift-dummy.m */, + 9B68E008BBF20F4741848EDDF2B82A6A /* RxSwift-Info.plist */, + 0BC849CCA664038F11F4F805A1D72D7A /* RxSwift-prefix.pch */, + D83242FBC909C2DC4C102061C1D985C7 /* RxSwift-umbrella.h */, + 363A4B179A004E5C46D5AEDEEFD28431 /* RxSwift.debug.xcconfig */, + 4B9AA9F85FB7028720BC48147A7340E8 /* RxSwift.release.xcconfig */, ); - name = Pods; + name = "Support Files"; + path = "../Target Support Files/RxSwift"; sourceTree = ""; }; - 886CED194CCA041E7E84D0BB03B1176D /* RxRelay */ = { + 79441F5504271AB6A89ABE42BD0982F4 /* RxSwift */ = { isa = PBXGroup; children = ( - A0580CAACDB221AEAEF5EE46900A661E /* BehaviorRelay.swift */, - B06D287CBC4CC7C094B544F533F4CA65 /* Observable+Bind.swift */, - A7A312365200557E6349C200AA39470A /* PublishRelay.swift */, - F34C096CAE0E50C543DD70356A57665F /* ReplayRelay.swift */, - EF1514228AEDC411709E7F1E8DD9A1A6 /* Utils.swift */, - C78FB39E81831511FC686752BEB1CB05 /* Support Files */, + 923E4FEB8C92DE3B193F1BEFF1FAFA36 /* AddRef.swift */, + 43CF235C9231F1361CBDDE0EC92FA624 /* Amb.swift */, + D37F407A84623FAB151F7CA5CCE94054 /* AnonymousDisposable.swift */, + 41F27E716EA312BE508938A789401C98 /* AnonymousObserver.swift */, + F344AD341770313494511A6FC34CD7F9 /* AnyObserver.swift */, + D946CD415A40593F4E87F434B15FBFB3 /* AsMaybe.swift */, + 7EAE90FF45150043BC9B9FFA197B7213 /* AsSingle.swift */, + 3B86CA8FB56D594D41CF699D266A6FBE /* AsyncLock.swift */, + AF5C52B068668E86B1D259B8C141CBE7 /* AsyncSubject.swift */, + AF03C202E24C0B84A8025CA0E8FFFDBC /* AtomicInt.swift */, + 565261C7427A20C48DEEE1D949EBD371 /* Bag.swift */, + 9193A575AD5A353845C82E257E9E18FB /* Bag+Rx.swift */, + B63E8E74CB465ACEDD8871E750E708C5 /* BehaviorSubject.swift */, + DD75294A445E2D81BD626118984385FA /* BinaryDisposable.swift */, + F67F863AAD2C0C759AC4DCDA316297A5 /* Binder.swift */, + 39BFF1F4303B0AE6E2D295DD49C76DC2 /* BooleanDisposable.swift */, + E5616C61981FF49AAC8EC1C8E02D6860 /* Buffer.swift */, + 07BFF01DC46CE2B8775DB7C2333A4181 /* Cancelable.swift */, + EF1E3D9A965EAC45B9F4E268B89C23F7 /* Catch.swift */, + C2BF8546CFD71D9F507D96AF1C570539 /* CombineLatest.swift */, + A8BB59E8726483F52D6D6971BCC1B3B8 /* CombineLatest+arity.swift */, + 2B74DB1EE448E983BD57207719A6ADAE /* CombineLatest+Collection.swift */, + C53AA73242D70049D68DCA526B69D005 /* CompactMap.swift */, + 1CA391017BD2A3678044F22FCDCC8E74 /* Completable.swift */, + CC17AA237A1B658AD0238FD93F0DFD62 /* Completable+AndThen.swift */, + F945667BC8F068155D11033D255A3993 /* CompositeDisposable.swift */, + E4607B3ED8CFA90C52AF18FFA2661128 /* Concat.swift */, + 6DCC34277014CFA748F33D63F2B0DDBC /* ConcurrentDispatchQueueScheduler.swift */, + 50813D9A78FAA9D509BC9BB9B2F3C28E /* ConcurrentMainScheduler.swift */, + 132F36A02348DB3BCDBDACFEF9CB787A /* ConnectableObservableType.swift */, + AFDC49E2EA080C69C9A651D20A8D625C /* Create.swift */, + 46AE8C1E9DACE1C8DDBD6126304A9EE5 /* CurrentThreadScheduler.swift */, + 5F38231AE4C38080DF74A2D0BEDD8BCE /* Date+Dispatch.swift */, + 871FB5539265859CC8CC49821EC0DE38 /* Debounce.swift */, + 173EBD30721F23C387A602599E4316B8 /* Debug.swift */, + BD8422862D3A378F92CAE72A63E771CC /* Decode.swift */, + 3A528F662FE12267714BB9BD1308F560 /* DefaultIfEmpty.swift */, + C7FBC5DD60EF61D351B0CA282AA2987E /* Deferred.swift */, + 4B8D740B9CD39CEBBE02FD72043BA317 /* Delay.swift */, + 0424BF5445C2DE265C48275A088BD3C0 /* DelaySubscription.swift */, + DECFD6204777ED86D3E84F3EFEAEE6C0 /* Dematerialize.swift */, + 8CAA0879259D2329E9EE3AB59EE9202D /* DispatchQueue+Extensions.swift */, + C57355D0496F6CA05BD3B095F859BF67 /* DispatchQueueConfiguration.swift */, + 6E371A1CF57F9459FCB12BC146AF7E84 /* Disposable.swift */, + 75F81D96A7B42E852FC0270A81AD5765 /* Disposables.swift */, + CB2FCE9EFC6B4AF321E0972F36214AFF /* DisposeBag.swift */, + DD704C7FD77889B382D1881BE82B57CA /* DisposeBase.swift */, + B918B07799B36CAEBE63F7D83D7839D5 /* DistinctUntilChanged.swift */, + 0640980150BB98AE63D6937157CEB1C8 /* Do.swift */, + 7B6279D00F667A0057801EF3AB863202 /* ElementAt.swift */, + F708BA46014EA7CCCE42123E340788AB /* Empty.swift */, + D658D77B0412C8504611038D50C9B8DC /* Enumerated.swift */, + 064F1CAB9993B8292FFC49F391E694E6 /* Error.swift */, + F0ABDFA66654E18EEE7E48DA5548533F /* Errors.swift */, + 112241935E9BE9CFD251FB234B0FB839 /* Event.swift */, + 557F4A5C3A1E88463A559F6771708562 /* Filter.swift */, + 75194C640C0A0483CC26C0CFC3517506 /* First.swift */, + 980E21F4EE794E4E1FF3E33D6882A259 /* Generate.swift */, + 003BE23129F6FB245F50432D5F89E24B /* GroupBy.swift */, + 1F36285EAC13EEE1ECCF3F9D7FD36466 /* GroupedObservable.swift */, + 4C710A6E5E7103CF26BF6DA1A3665A55 /* HistoricalScheduler.swift */, + 593ECDF08EB42221F442B0B0BA4E09EB /* HistoricalSchedulerTimeConverter.swift */, + 257DE2F860194DE5AA9E2B2782DF8793 /* ImmediateSchedulerType.swift */, + 01D3FF377028729D3E8608459718B6E0 /* Infallible.swift */, + 4DE5128DFD130806F20EC429CA451C0C /* Infallible+CombineLatest+arity.swift */, + 852B8D3959EFB94CF388478FD427AA2C /* Infallible+Create.swift */, + F1013EB27F868D358C47ED382D6D4F89 /* Infallible+Operators.swift */, + 7F3AD1EC697290EA4E4FAC118C308D98 /* Infallible+Zip+arity.swift */, + 03AD707277DF16D02FC728818FCA494F /* InfiniteSequence.swift */, + 730E778D74EC5F08A80D328E71B9589A /* InvocableScheduledItem.swift */, + 6CE26D5D8DD5D6141DBE1A83DB70651F /* InvocableType.swift */, + 8E48048F9DE3CE9CDFD07D96C43092EB /* Just.swift */, + 4104B378EA3EBFE66129D192B22A2627 /* Lock.swift */, + 2103F4BAA235B84CE74EEACDD70D945E /* LockOwnerType.swift */, + 3B5D82CBB58DAD651E4DC89985DC41F8 /* MainScheduler.swift */, + 57446328CADAB2C557D69630490DD5BD /* Map.swift */, + D23F046BFB31018CD45DF786AA3F3152 /* Materialize.swift */, + 17878B482853B987E43D970E0F91E0B5 /* Maybe.swift */, + C3C8550C0F6D06103D8A56924D191475 /* Merge.swift */, + 7C9BC0E9772C9C6C7981B6B3A3663C06 /* Multicast.swift */, + 93D9788DA7EEE3354ABA2E15C9D71728 /* Never.swift */, + 7269D3077B11B2C74F5650E6D52258ED /* NopDisposable.swift */, + C2BFEA63DFDBE33D8A71974A9D6C7CEC /* Observable.swift */, + 81A38A41FF433485F61118C92056AB27 /* ObservableConvertibleType.swift */, + 0EB397BBE2053179721ACC128AC15CEA /* ObservableConvertibleType+Infallible.swift */, + 8B44EDE211FB067BAA8C79521F169355 /* ObservableType.swift */, + C7182CF8BE4608290699B6B2CF78E388 /* ObservableType+Extensions.swift */, + F7F31A302B3F3DC88ABBBAEBC47911DF /* ObservableType+PrimitiveSequence.swift */, + 56060B7A57AAEBE6E3946AA4BD3854D5 /* ObserveOn.swift */, + FD6A2B3CDA9EA6E76F57EDAB7349515F /* ObserverBase.swift */, + D7E8F79E7DC88DEB6DFACA82D883EE9E /* ObserverType.swift */, + C8E167AE7AF784540620A299389233DC /* OperationQueueScheduler.swift */, + 2187E0B6C891F3F1767EE5994A0A04F1 /* Optional.swift */, + 244E51A33CB5B29ADFE25976FDA0E00E /* Platform.Darwin.swift */, + 425614E9FB485B7AFD1395F3890AEB4F /* Platform.Linux.swift */, + D18BC0612ED16A755787EC28623BEA19 /* PrimitiveSequence.swift */, + 8EE39E5285C895DFB30377387C2BC245 /* PrimitiveSequence+Zip+arity.swift */, + 267DB70A0C2AB28FC178E80A0718B8AB /* PriorityQueue.swift */, + 5F43B8F01A543777B15BE6850ED311C5 /* Producer.swift */, + 801EA459B5D61FCD65C817EB048EAB29 /* PublishSubject.swift */, + 329CA141F6D77E3069C111A94A5B2892 /* Queue.swift */, + 8D165677590A732F5E46A334914AF9F1 /* Range.swift */, + 1DAA98713A8129DA8D7F67CFEB63F07A /* Reactive.swift */, + E43A403DE21567DCAB3F49FC518B26B9 /* RecursiveLock.swift */, + F7E8ED230B0233D8CA891E48B052C4E8 /* RecursiveScheduler.swift */, + 993CAA60E070CF39B9426C3F90BD63E3 /* Reduce.swift */, + B001EE5D9F141B15F1B524D9D1CE6FF5 /* RefCountDisposable.swift */, + EE5F5D65B6D06DECF5638D0B4908DC4F /* Repeat.swift */, + CDF053478C3D4A12F08977D089A9185F /* ReplaySubject.swift */, + 63E8E04E3E7BD0E30508D61F734DFC14 /* RetryWhen.swift */, + B0A7A8B1E275B8F3D59D65566FA08C2D /* Rx.swift */, + AEFA60C5F16D18879D7BA1A6092A068A /* RxMutableBox.swift */, + 70932FD1797B63C347443B74252917E8 /* Sample.swift */, + 3D762331D58A21757B046C90540486FC /* Scan.swift */, + E99C8AF3D55554B142A4F58C1CD027E4 /* ScheduledDisposable.swift */, + 7033B5BDCF5E1938C2218057A72A2ACD /* ScheduledItem.swift */, + C260175CDEEFDC2E0924E1EC569B22CB /* ScheduledItemType.swift */, + 49A05763AF9D42793D8CEFE5AFD48977 /* SchedulerServices+Emulation.swift */, + 90437FAB08E287AE379C7C8CFACED79F /* SchedulerType.swift */, + 4CAE89435EE2619F199768480BA9B3AC /* Sequence.swift */, + D514C0BFAF080B34155E84CCBC3F2AD7 /* SerialDispatchQueueScheduler.swift */, + F2B90B3B71B154BF22849D356E334730 /* SerialDisposable.swift */, + F70ECF0CFF0163ADABFC3B6C7D328962 /* ShareReplayScope.swift */, + 4C58CCC55F3E94E451DEEC457570FD6F /* Single.swift */, + 716C98F332A803D36F35817F3A5E10ED /* SingleAssignmentDisposable.swift */, + D5F9933EF3E2D0E5C9A38450DA95C940 /* SingleAsync.swift */, + AD15E723F2844714489FFB45590ABD63 /* Sink.swift */, + 3C890F215AF0CB31979E34F7A9F3B85C /* Skip.swift */, + F153DE82AECB4A5F740D245E96EBFDBF /* SkipUntil.swift */, + 453B4F0BA86A5AFEC030E0DB9B080DA8 /* SkipWhile.swift */, + 482E10370BAB6DE666A35873DE1DA9AF /* StartWith.swift */, + 103354D756EEF3F7108DEC03A6165EEC /* SubjectType.swift */, + 8F1E1808D922AA079EF80B4EF1349FBF /* SubscribeOn.swift */, + CD27C6BF074BBDBCC0E702778BA185B3 /* SubscriptionDisposable.swift */, + 0762669681B2AC7CE7998DDDB2D3F1F2 /* SwiftSupport.swift */, + E4BF685D4B1DD3AC80C1A61C3A326CDD /* Switch.swift */, + 35BF645AE8BDB43F5F91AA91349F1B63 /* SwitchIfEmpty.swift */, + F577F1C935B3E560C16CE20C6521266B /* SynchronizedDisposeType.swift */, + 7CFB93251A99DD08018B991E538ADD37 /* SynchronizedOnType.swift */, + B06E8014F3D0084CBB2E358F32E9DEFF /* SynchronizedUnsubscribeType.swift */, + 5425A30F69C058EBD3CECC3192A4A455 /* TailRecursiveSink.swift */, + 662CE261C0D358E5AE55613422CCDBCB /* Take.swift */, + FC0D711F5C8019E955B578378608C5D1 /* TakeLast.swift */, + 78CCC4722D47EFB9F36D15D6075781DB /* TakeWithPredicate.swift */, + 10683973D347C94E5EAFC16D41AFD67E /* Throttle.swift */, + 20BC4B195BA7EB8AF77DA60381FCCD43 /* Timeout.swift */, + E233119C4C85536D7158A45BC58EE2BC /* Timer.swift */, + 33B20AE498859D4D4AF71FD9B168684F /* ToArray.swift */, + 2934C5C2C05618A3D6A55FE1795714E0 /* Using.swift */, + F9F6C121115219E23559F019FF606BCD /* VirtualTimeConverterType.swift */, + 09E5E4F2BCD53E7623C2C55EA38378DD /* VirtualTimeScheduler.swift */, + E98E87EE662818FA7ED50231400C4D27 /* Window.swift */, + BFC3BE7AF4B17BE5C089702D819FCC4D /* WithLatestFrom.swift */, + DD97EB9B9E811F96C7484EB462830C06 /* WithUnretained.swift */, + E95780524ED5621196640AB551C752A4 /* Zip.swift */, + C6CEDE2E14A6455694E1E27F4AC1DA6B /* Zip+arity.swift */, + 431CE5CA440EADE478463371D8940E0F /* Zip+Collection.swift */, + 71054607DCDF5FA0EE1ABF0297462930 /* Support Files */, ); - name = RxRelay; - path = RxRelay; + name = RxSwift; + path = RxSwift; sourceTree = ""; }; - C458C4025B7498BC6B0A79D88FDF1AE9 /* Support Files */ = { + 833FCBF62B1183E9D709B62B35F0A0AE /* Support Files */ = { isa = PBXGroup; children = ( - 6C867006979B630B992855A4332250EA /* SwiftLint.debug.xcconfig */, - 7E5A11BFD4B2349FE0800D0FEE107B6E /* SwiftLint.release.xcconfig */, + A8BD652C0FF5C63E1A0B2F5394B2AA62 /* Alamofire.modulemap */, + 22AAD42AC2A848D8F7BFEFB4DC3A8879 /* Alamofire-dummy.m */, + 0574C75A44746F41A2D4CE995EFFC811 /* Alamofire-Info.plist */, + F56916BB23B56CC212997FCF13F2D6C3 /* Alamofire-prefix.pch */, + CECE3D4B1535B76770B404D8B990A429 /* Alamofire-umbrella.h */, + A360A1E748495A656A23264F856CCF30 /* Alamofire.debug.xcconfig */, + 0AD7897AC94CD3CD139D7249BCBA09AA /* Alamofire.release.xcconfig */, ); name = "Support Files"; - path = "../Target Support Files/SwiftLint"; + path = "../Target Support Files/Alamofire"; sourceTree = ""; }; - C78FB39E81831511FC686752BEB1CB05 /* Support Files */ = { + 86E5E74BD96D609035F0903E45CDD9C9 /* Support Files */ = { isa = PBXGroup; children = ( - 07EE5CA97A79FC56E99B357F91998429 /* RxRelay.modulemap */, - 64388E578D1FB97E4DB5775A469337F1 /* RxRelay-dummy.m */, - 9BD7648ABD334379BE8CD01DF07615E6 /* RxRelay-Info.plist */, - 6EDA7483F44DEE73680237D089137E9D /* RxRelay-prefix.pch */, - 742D5848876230A2E30823D4FDE0FDB0 /* RxRelay-umbrella.h */, - 24701C2CDA783D537E98D65A2919ADBB /* RxRelay.debug.xcconfig */, - 7E8F125BC91320E99EBE78FEE1309CDA /* RxRelay.release.xcconfig */, + F0FABE638332DAE9CB1544D1EADB9154 /* RxRelay.modulemap */, + 46E3B0C82A8F4E4AF7951C604C8D41F8 /* RxRelay-dummy.m */, + 645A3BDD411B7668A9CB4FF049051177 /* RxRelay-Info.plist */, + 8EF52747268CDA52F3EB2AD2E9D3A4DF /* RxRelay-prefix.pch */, + BD18805FCE30E1005F6FC4198C5ED48E /* RxRelay-umbrella.h */, + 0409B4163021C318D05F2A0F97350868 /* RxRelay.debug.xcconfig */, + FD6E426F20C80EA25A69B8D17C2C9DFB /* RxRelay.release.xcconfig */, ); name = "Support Files"; path = "../Target Support Files/RxRelay"; sourceTree = ""; }; + 9CD96962E033D1330F3B3D5E4AE72F4C /* SwiftLint */ = { + isa = PBXGroup; + children = ( + E9B0D39F3F227EAF75AA73A5B24FD16B /* Support Files */, + ); + name = SwiftLint; + path = SwiftLint; + sourceTree = ""; + }; CF1408CF629C7361332E53B88F7BD30C = { isa = PBXGroup; children = ( 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, - D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */, - 7EA5F21C185E2FBACE494BCD6621C8CE /* Pods */, - D72BCECCE8D490C112590BC0D0ACF3EC /* Products */, + 1628BF05B4CAFDCC3549A101F5A10A17 /* Frameworks */, + 5F0D48E69705E7F4F650884B7218A0C3 /* Pods */, + 0C2CD72DB96BBF31047FE8A315A451C9 /* Products */, 50B0FC5775B5B0DF52EE0E71B404AF36 /* Targets Support Files */, ); sourceTree = ""; }; - D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */ = { + D093A27314299CF82C3757198933365E /* Alamofire */ = { isa = PBXGroup; children = ( - 578452D2E740E91742655AC8F1636D1F /* iOS */, + 1CE9464205009D39C62EE5E3B85E6260 /* AFError.swift */, + 378EBA5E2DCED169738F8B81FEC144CE /* Alamofire.swift */, + 0DFAFE2B7445F5066808C50D6442C72C /* AlamofireExtended.swift */, + 581CD3FDB8146C432DAD2AE38AE8596E /* AuthenticationInterceptor.swift */, + F65EFD9FCE2C86F5C16EF6707DAEE01A /* CachedResponseHandler.swift */, + AFA0FDF7B29DB45C9207791DA9305107 /* Combine.swift */, + 03B62EC386D75F6A3C259E3A603A4CF8 /* Concurrency.swift */, + E358CE05FC83CCB4181BCD48A6808920 /* DispatchQueue+Alamofire.swift */, + 4CD6F37FF01714E62B05CCE204A180FE /* EventMonitor.swift */, + 5ECFFF39AC84FF510A575BBBD6BA4B0A /* HTTPHeaders.swift */, + 7388BCBEE8E3D8292F5D6253EE8E2C5E /* HTTPMethod.swift */, + 8FC6857CE4BA0536407B134EE1028C0D /* MultipartFormData.swift */, + 65FA1855B83C5BE32DA991D72EEA3564 /* MultipartUpload.swift */, + 0F1BCE55561F2EDA941C3A3A1284DC55 /* NetworkReachabilityManager.swift */, + 44621BE174840A776DA54345ED8C22F6 /* Notifications.swift */, + E6F6DD6B4E80ED9DDB1730AB62B8CDBC /* OperationQueue+Alamofire.swift */, + 97A8FF5FA28E690E10D289E1D57F7930 /* ParameterEncoder.swift */, + 1B20B9F6EB6E0D8B0DCE2E0A406D8986 /* ParameterEncoding.swift */, + 3673AC5B3124EC7A5ADE41E8D4A32E38 /* Protected.swift */, + DE088314501929D3EC446CF926925ACA /* RedirectHandler.swift */, + E62DDC544E8AC865B9AA08706E6FC139 /* Request.swift */, + C10859DDF0B86C7AB30D77FC23A13C38 /* RequestInterceptor.swift */, + 32FFEA205095DE804BCFB4BA3E297506 /* RequestTaskMap.swift */, + DED707571AA14733539CD9ED34AD9CD3 /* Response.swift */, + D89AF9F1C03B2EA8FBCB02834E6E7DB9 /* ResponseSerialization.swift */, + D27530937BD04E067916C314B8DA2210 /* Result+Alamofire.swift */, + FD7918FA9555E6D24F7C7C37B53D3FC5 /* RetryPolicy.swift */, + AA8EBC7BECC7DD0598F14332FCC97995 /* ServerTrustEvaluation.swift */, + 3126D57CF6D0BC79B9BD8D382FDFF41F /* Session.swift */, + 581BAF255A6D18A23D9B2B8586160060 /* SessionDelegate.swift */, + 2EB486C2DC92FC85AE2811D80085646E /* StringEncoding+Alamofire.swift */, + 54CADC59F472FDD873ECC8AC0334ADF3 /* URLConvertible+URLRequestConvertible.swift */, + 8B6565DBDAB6E638F9B180AC2B084B0E /* URLEncodedFormEncoder.swift */, + 734C97C73C262E10D878B235A0B0B183 /* URLRequest+Alamofire.swift */, + 32BA8073424D0DF7ECECDDB2EF816A68 /* URLSessionConfiguration+Alamofire.swift */, + 20C5AA8122AA25F6AE43D02B1AB787B4 /* Validation.swift */, + 833FCBF62B1183E9D709B62B35F0A0AE /* Support Files */, ); - name = Frameworks; + name = Alamofire; + path = Alamofire; sourceTree = ""; }; - D72BCECCE8D490C112590BC0D0ACF3EC /* Products */ = { + E78FFAFA9DCC7AFA082533F2102E92D3 /* RxRelay */ = { isa = PBXGroup; children = ( - 8A126E0270200C843AF51E993B2E277F /* Pods-Instagram-Clone */, - BC432FD48A5932251F1CAFBC4BF74894 /* RxCocoa */, - FF8B264DFE802855D5D67E7CDDABFC3C /* RxRelay */, - 809C5FAB588354C9BA37DC3EAB8CB45C /* RxSwift */, + 8DFCC0632F76CF0BA9C49B9A2B33DF57 /* BehaviorRelay.swift */, + 0367676A099A476FEA0C5CB232616A22 /* Observable+Bind.swift */, + E1BC592E13CDF07E2B7ECDFED477DC79 /* PublishRelay.swift */, + EA7D0DE84DEAC2C941CAF698E76580EB /* ReplayRelay.swift */, + E96DDF40C7F94101633F7E4244996BF6 /* Utils.swift */, + 86E5E74BD96D609035F0903E45CDD9C9 /* Support Files */, ); - name = Products; + name = RxRelay; + path = RxRelay; sourceTree = ""; }; - EDF7DABE160019C6A29E1438680F4A3B /* Support Files */ = { + E9B0D39F3F227EAF75AA73A5B24FD16B /* Support Files */ = { isa = PBXGroup; children = ( - 6C6F8A7DAB39B910A381FDC4AC70E3A0 /* RxCocoa.modulemap */, - 44C06230C881B6028853B66557DBFEE6 /* RxCocoa-dummy.m */, - 3C8A1A3FEB0F250D55F66A3C867BBDB9 /* RxCocoa-Info.plist */, - FDD223851F1F5B630321574515DCFEC2 /* RxCocoa-prefix.pch */, - 1C61DA0F4B8F6066A14AEF98A1D31D00 /* RxCocoa-umbrella.h */, - 42E8C86A17D8344F4AFE300FDA80AB49 /* RxCocoa.debug.xcconfig */, - 9AE802EE93AC891F8BBD3595F4F97123 /* RxCocoa.release.xcconfig */, + 29E0682772F7E3BF82479D100F042D2A /* SwiftLint.debug.xcconfig */, + 2A06AA26688719BE78A832A68E8139C0 /* SwiftLint.release.xcconfig */, ); name = "Support Files"; - path = "../Target Support Files/RxCocoa"; + path = "../Target Support Files/SwiftLint"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 02590C189318837042D780EEB55E54BA /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - FE28EF50F750DD767ADFC545A6C8EC72 /* RxSwift-umbrella.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 1636FCAD17E4800F64DBA2B1BA737C7D /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -1165,19 +1321,35 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5224D89EB05C475C9328577087D4C754 /* Headers */ = { + 52E6F7B26483BE3BC9393C6C05D32424 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 005B319B494ED2DAA239B9939A504DFC /* Alamofire-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5F12218C384B0782A7B9E7CCD9DE33AF /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 8D699C4D8028F3076F60D47B9C88E45D /* Pods-Instagram-Clone-umbrella.h in Headers */, + B5ECDE3256892020DC7049182FF91713 /* RxRelay-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; - 64E2FC0BB1561FA07D6AAED2674D13EF /* Headers */ = { + 7C9114468E0F694BB9726AA46DFE7B8D /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - CFDB789808F3EFC72BD379080F6D4F1B /* RxRelay-umbrella.h in Headers */, + B7A2022F7043A3980995817804825B79 /* Pods-Instagram-Clone-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DBA05D3A7A753F2D8AA94658DD532754 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + BF73656CDE078B545CD5F4AEA5A038FC /* RxSwift-umbrella.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1186,20 +1358,21 @@ /* Begin PBXNativeTarget section */ 433DABF64CF6C5984E8BADB4EEFF0346 /* Pods-Instagram-Clone */ = { isa = PBXNativeTarget; - buildConfigurationList = 6F222468B6B50703AAA3B9D52DF18D03 /* Build configuration list for PBXNativeTarget "Pods-Instagram-Clone" */; + buildConfigurationList = 379E8A1260B94A013AE0116EF9119546 /* Build configuration list for PBXNativeTarget "Pods-Instagram-Clone" */; buildPhases = ( - 5224D89EB05C475C9328577087D4C754 /* Headers */, - B91D9451C23913E7C8A6B25EB289F975 /* Sources */, - 0705890A408D203E7861663DF02E14CE /* Frameworks */, - 0CF16EA718CF4CB91433EC7791E1DD3D /* Resources */, + 7C9114468E0F694BB9726AA46DFE7B8D /* Headers */, + F15AD905B04CC8E3EC976C8D01C24366 /* Sources */, + 9C601D122E249EC454C0E310DE3026DD /* Frameworks */, + 05798F2B6F0B2E208D01F9D55DCB3C8B /* Resources */, ); buildRules = ( ); dependencies = ( - 35C8021D50D8ADD21B141371B6A5EE80 /* PBXTargetDependency */, - D2771474175712AEFE74B4DED8CFFE59 /* PBXTargetDependency */, - 7C69B27CCBBAF437804D9913D4D7C73B /* PBXTargetDependency */, - C9AC0C2C7C9F1F1D1A3594F0245B2E54 /* PBXTargetDependency */, + B9F3F03975FF54333708135C0DDE0C08 /* PBXTargetDependency */, + 1DDAA5965B14DE1774117F7962FD9B72 /* PBXTargetDependency */, + C902207C970CE58DDCADC9925735DC92 /* PBXTargetDependency */, + 1174C85B4B0A901D4393B200578B159D /* PBXTargetDependency */, + E8DE41A08A694D2D3B024F9C97D7619D /* PBXTargetDependency */, ); name = "Pods-Instagram-Clone"; productName = Pods_Instagram_Clone; @@ -1208,17 +1381,17 @@ }; 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */ = { isa = PBXNativeTarget; - buildConfigurationList = D36ADE6C0C851C68584DBA4B11D3F818 /* Build configuration list for PBXNativeTarget "RxRelay" */; + buildConfigurationList = 5CA471FA9BA4D8AEB61463D4594FF33D /* Build configuration list for PBXNativeTarget "RxRelay" */; buildPhases = ( - 64E2FC0BB1561FA07D6AAED2674D13EF /* Headers */, - DE80953551E4BA26C461B657192C6F1B /* Sources */, - 9EF7D08E3C67C1796D9410DF9F9AF313 /* Frameworks */, - 962107FD8995A763FE1B0F191CD7FE51 /* Resources */, + 5F12218C384B0782A7B9E7CCD9DE33AF /* Headers */, + 1E6334E7E0D39BE6FC5C955C5E90A2BF /* Sources */, + 6D1DDCBE282BCAF633EDA6632D43FD3C /* Frameworks */, + 3A735B97DA560D94302BD92F744ACEF0 /* Resources */, ); buildRules = ( ); dependencies = ( - EC0D889F4042FDDC39349AC314078D0E /* PBXTargetDependency */, + FDECC8D7B9E662002E278A9B42D9EA9C /* PBXTargetDependency */, ); name = RxRelay; productName = RxRelay; @@ -1237,8 +1410,8 @@ buildRules = ( ); dependencies = ( - 3D152496571B94A07486C3AB5F2B891E /* PBXTargetDependency */, - C0F11143C2946D639E3E3882511F4AEE /* PBXTargetDependency */, + 81E18313172EB5F74DD64716D0BA62A9 /* PBXTargetDependency */, + 55DBD1FAD1E1ED3D72B3EC75692FAD30 /* PBXTargetDependency */, ); name = RxCocoa; productName = RxCocoa; @@ -1247,12 +1420,12 @@ }; EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */ = { isa = PBXNativeTarget; - buildConfigurationList = 8055F1D78688E5422827AD5F695641D5 /* Build configuration list for PBXNativeTarget "RxSwift" */; + buildConfigurationList = CE9D24514F4FD09A1AB2DFBBD2E4AFE6 /* Build configuration list for PBXNativeTarget "RxSwift" */; buildPhases = ( - 02590C189318837042D780EEB55E54BA /* Headers */, - A3E66903E340320ACD859EF9281EBE62 /* Sources */, - E7C204DC6B7DEFD4553559C2C873AFD1 /* Frameworks */, - E137E7087E35554D68F6EB3C96474BCB /* Resources */, + DBA05D3A7A753F2D8AA94658DD532754 /* Headers */, + E655BC65A74D7C39E79FB3C492044353 /* Sources */, + 55DC75CEFCA651A08098DF1B82B0AF75 /* Frameworks */, + 8ED0F9F9813C86E0F98BCD6DCC83EEFC /* Resources */, ); buildRules = ( ); @@ -1263,6 +1436,24 @@ productReference = 809C5FAB588354C9BA37DC3EAB8CB45C /* RxSwift */; productType = "com.apple.product-type.framework"; }; + EAAA1AD3A8A1B59AB91319EE40752C6D /* Alamofire */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8A212264186B8822192F9C369D7DE4BB /* Build configuration list for PBXNativeTarget "Alamofire" */; + buildPhases = ( + 52E6F7B26483BE3BC9393C6C05D32424 /* Headers */, + F5D2A45FBA06D86A537CB441D5BF4FF4 /* Sources */, + 15DC142A7EE833251AA37FC8E2B8E01F /* Frameworks */, + E9D4145FA41F60FFAB33A07796D9ED97 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Alamofire; + productName = Alamofire; + productReference = 5D797E9A5C5782CE845840781FA1CC81 /* Alamofire */; + productType = "com.apple.product-type.framework"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -1281,10 +1472,11 @@ en, ); mainGroup = CF1408CF629C7361332E53B88F7BD30C; - productRefGroup = D72BCECCE8D490C112590BC0D0ACF3EC /* Products */; + productRefGroup = 0C2CD72DB96BBF31047FE8A315A451C9 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( + EAAA1AD3A8A1B59AB91319EE40752C6D /* Alamofire */, 433DABF64CF6C5984E8BADB4EEFF0346 /* Pods-Instagram-Clone */, 7AD0C6DCDC9CEC8A3C7C10C7FEE07BE6 /* RxCocoa */, 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */, @@ -1295,14 +1487,21 @@ /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 0CF16EA718CF4CB91433EC7791E1DD3D /* Resources */ = { + 05798F2B6F0B2E208D01F9D55DCB3C8B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3A735B97DA560D94302BD92F744ACEF0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; - 962107FD8995A763FE1B0F191CD7FE51 /* Resources */ = { + 8ED0F9F9813C86E0F98BCD6DCC83EEFC /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -1316,7 +1515,7 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - E137E7087E35554D68F6EB3C96474BCB /* Resources */ = { + E9D4145FA41F60FFAB33A07796D9ED97 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -1326,189 +1525,189 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - A3E66903E340320ACD859EF9281EBE62 /* Sources */ = { + 1E6334E7E0D39BE6FC5C955C5E90A2BF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A877585244D5066F98821D45EF0715EE /* AddRef.swift in Sources */, - 6721B4F8556A903296754D565939E2A6 /* Amb.swift in Sources */, - C58770A749AB10BFF4C26B35117881FD /* AnonymousDisposable.swift in Sources */, - 5089A93E147C25A4660F838231150204 /* AnonymousObserver.swift in Sources */, - A416110399B7A9BDF7D85DF2F597F00C /* AnyObserver.swift in Sources */, - 72C98497431AE93DFDBC57EEE2D20C35 /* AsMaybe.swift in Sources */, - 770B72F721A4554BB4C3A4F2556B8045 /* AsSingle.swift in Sources */, - B52B575A4656A46645F3B5A999917A14 /* AsyncLock.swift in Sources */, - 6824A31E76DD054D44A3B14B69335858 /* AsyncSubject.swift in Sources */, - EAE1752C0AEDE31E5C434F36D0BD3FB9 /* AtomicInt.swift in Sources */, - C6A45564D562250B2B44FEEA9817DD8E /* Bag.swift in Sources */, - 377F7F2ACDAEC9FA1E6A515894AC97C6 /* Bag+Rx.swift in Sources */, - 492CE2AA2B9DDE29FA77A9D29BFA88D6 /* BehaviorSubject.swift in Sources */, - 37D6A7E0FD0E450761120C976F95EA73 /* BinaryDisposable.swift in Sources */, - F7AC44763C0C15071FD456A0AEF1D1C9 /* Binder.swift in Sources */, - F59A01A28BA499C3731E4987D3CD8C05 /* BooleanDisposable.swift in Sources */, - 7F27F23934F685925D4E1C3629F8B5F7 /* Buffer.swift in Sources */, - FEEEBA2D9A2CEAEBC53F4FBB810F0B26 /* Cancelable.swift in Sources */, - 527135A13489F35CD40B860DB3C9AF82 /* Catch.swift in Sources */, - F559C7E04013E3D7F5CCE342533823DB /* CombineLatest.swift in Sources */, - B39AE6FCDDC339B7EA69C041DAE7FED2 /* CombineLatest+arity.swift in Sources */, - C328725EBFF411F9858C9326D3ABD0F3 /* CombineLatest+Collection.swift in Sources */, - E39D71E6483501221BACD658EC4E8E2D /* CompactMap.swift in Sources */, - B53149262AC23819BDE17E15E4CEAC8B /* Completable.swift in Sources */, - 70C2D5C7F8CE4C996556072B546BAB01 /* Completable+AndThen.swift in Sources */, - 99B75C980B7F5E81A5CFCCACB57ECEEC /* CompositeDisposable.swift in Sources */, - 4D19C1FCCFA37B3EEBCD874A8A4A5AD3 /* Concat.swift in Sources */, - A8FDCEA60F22D974B678CC68FC0FC933 /* ConcurrentDispatchQueueScheduler.swift in Sources */, - 358F0A3017B7486ADE25FD5ADFCA7904 /* ConcurrentMainScheduler.swift in Sources */, - 66451B72DFC713F4784A0C107AE67C34 /* ConnectableObservableType.swift in Sources */, - 98BBA8C13C9C407DDB402708D6C1DDFC /* Create.swift in Sources */, - 9A0606B12634DDED8A0EA1EE72FD56B6 /* CurrentThreadScheduler.swift in Sources */, - BB95DBF30DBBC9F53363027CE1BB422B /* Date+Dispatch.swift in Sources */, - A9A21661CE07EA9A179E3D077CB5013A /* Debounce.swift in Sources */, - 5084C64F70AC0E22C44BD5B465F08BA7 /* Debug.swift in Sources */, - B75EC99EE9B6D74230B05B192A373DBF /* Decode.swift in Sources */, - E1056A74E23F1D4CC7D6E54CF67A8E0F /* DefaultIfEmpty.swift in Sources */, - B43BF0B2405F3E9368D5F86AD2834688 /* Deferred.swift in Sources */, - 668A595C1895EA60A365B0CFF9636846 /* Delay.swift in Sources */, - F9D01BFEF79C107A5AB6BC5E4FFDF2D7 /* DelaySubscription.swift in Sources */, - 19D3E1EBDFC58CA48AA3F508FB147EAF /* Dematerialize.swift in Sources */, - 6FD8007E70E3D3FE65EEB9A576ACE6E0 /* DispatchQueue+Extensions.swift in Sources */, - ACB7287C66F652838DE45D5FBFD441A1 /* DispatchQueueConfiguration.swift in Sources */, - E32D6DF371CE8D8E2519A46D4252C7A5 /* Disposable.swift in Sources */, - 0FAC1DC2496E52AE639614E453BA592A /* Disposables.swift in Sources */, - 9521D073AB7B8F3F4D8198CA514AD699 /* DisposeBag.swift in Sources */, - 446F77EE27F2DE7513D3D43FDDD4BBFD /* DisposeBase.swift in Sources */, - E6CE8DEF5D58911F515C3085D02B5FD5 /* DistinctUntilChanged.swift in Sources */, - 1F49C9115FC34EA07139974045770A67 /* Do.swift in Sources */, - 985C1E80CAD53D9EBF3C366FC3B90B1C /* ElementAt.swift in Sources */, - 7B9E0259D63E7DC7C4A15A116CFD20E3 /* Empty.swift in Sources */, - D8077E1CA5DB15B51BEBCC634FF30FCB /* Enumerated.swift in Sources */, - 33BFC526BF10EBF07C927DFC75AFF826 /* Error.swift in Sources */, - E15B608DD9C58C27138F0658DF39EF89 /* Errors.swift in Sources */, - 3B8549624DDB175C02265F177609376F /* Event.swift in Sources */, - EE0972ED958070541E8C1ABBE50AD053 /* Filter.swift in Sources */, - 77DE7B1A171A8A834D1C829CAB53DC8E /* First.swift in Sources */, - 19FABB4A23630183D55E62C03BEE35D4 /* Generate.swift in Sources */, - 194D143B3484967A99C5803AF4FEAA34 /* GroupBy.swift in Sources */, - 2AFA355C5FFE96278B4F2ADA01AD68A6 /* GroupedObservable.swift in Sources */, - C0CBBD9D2153C76CC4A124321F66DF55 /* HistoricalScheduler.swift in Sources */, - C5A26E0FE94871E9445753078C059AFF /* HistoricalSchedulerTimeConverter.swift in Sources */, - B319ABE0B5A79B265AB9EC265BA32FDC /* ImmediateSchedulerType.swift in Sources */, - 062D7A155A2447CC2BE51F038B44312D /* Infallible.swift in Sources */, - C435863C953D4CC4E88EA84B950E710F /* Infallible+CombineLatest+arity.swift in Sources */, - A52A96F5C18BB006098DEC94C4E8CC3D /* Infallible+Create.swift in Sources */, - 2375EDAD8E10B3DF818E18FC14D3E509 /* Infallible+Operators.swift in Sources */, - 0B91A134E90374448E0CFDB3235525B5 /* Infallible+Zip+arity.swift in Sources */, - 45358BFBB698E1F6B71BFC5CAEC76FC4 /* InfiniteSequence.swift in Sources */, - EA057AAB3D8A543AABA9C6BB05EA2547 /* InvocableScheduledItem.swift in Sources */, - 05F5C384CDC4BDD7B01E63C3F82D9569 /* InvocableType.swift in Sources */, - 21DC0A2D2A64CB7511A4FA138072161C /* Just.swift in Sources */, - 5B06F69235E0E8E680E6A4F68951A8AD /* Lock.swift in Sources */, - DE8F6179F22AA4E593D23C6CD4529FF2 /* LockOwnerType.swift in Sources */, - CB88E214712F902A3BDBC2B1582D80B9 /* MainScheduler.swift in Sources */, - CB609631B3F62445002C65C34BFE747A /* Map.swift in Sources */, - 3881A1E025B3561AE179F9FDAE57187E /* Materialize.swift in Sources */, - 1D1E1B6DB82B5D478BBFEB38088B1651 /* Maybe.swift in Sources */, - 6221DA074DD5611302639D8136AAB3BD /* Merge.swift in Sources */, - AC813524AC3288D8D7211D0460FEB9C0 /* Multicast.swift in Sources */, - ACC6FE2A0154AEFA723F19B387B98306 /* Never.swift in Sources */, - 9F91138ACA7962F49DB2CDA2EB898ED8 /* NopDisposable.swift in Sources */, - 289B486CE0DC17D17817EC988F341CE9 /* Observable.swift in Sources */, - 2D1B4021AE7EB95A36DAFE3CC858082B /* ObservableConvertibleType.swift in Sources */, - 40AF681341B77C5E2896E507F65E8B39 /* ObservableConvertibleType+Infallible.swift in Sources */, - 7C503EFAA5E9AD2FA2A436E8C1A75A44 /* ObservableType.swift in Sources */, - 4FA389E8CCD45D266A3FBB6F8A445855 /* ObservableType+Extensions.swift in Sources */, - 585F7A5B3484C702B1142C4D99F09E0E /* ObservableType+PrimitiveSequence.swift in Sources */, - B5CC471C9EA6B4D9757FE55A807726BE /* ObserveOn.swift in Sources */, - 52CDD18140E6FE4BE418B6FBDCA1F4B7 /* ObserverBase.swift in Sources */, - 8E1CC3D54AD8D9D06780C564C24D18AA /* ObserverType.swift in Sources */, - 0295CFA000CC0A05833225BE4966E6F5 /* OperationQueueScheduler.swift in Sources */, - C3C83569578601F779F1BE1DB50386DD /* Optional.swift in Sources */, - D1E7DB962D3779DFE587BCED867E7BF9 /* Platform.Darwin.swift in Sources */, - 5FB4CCABB0B94E40E68A7A4142E487C2 /* Platform.Linux.swift in Sources */, - F67B050988818CB46229D1EC0860F7B4 /* PrimitiveSequence.swift in Sources */, - 7E8F6522AB2F462F4C8E7DDBCE073FFC /* PrimitiveSequence+Zip+arity.swift in Sources */, - 02BC9CD938596861D06F0BF200DBD5D7 /* PriorityQueue.swift in Sources */, - FD7B95C9708C785ED9BBDF504D29C994 /* Producer.swift in Sources */, - 99BAEAC4A09CBE44FA6D6772C18278B6 /* PublishSubject.swift in Sources */, - 80487E786F9E8595C97CC019819F54DB /* Queue.swift in Sources */, - FFDEBFF354E1D73A5836B08A98B57E82 /* Range.swift in Sources */, - D3179A1825ED194F1972EA6A3F0DD85B /* Reactive.swift in Sources */, - 0D4D63DB8DC6713171DBD122D23783F5 /* RecursiveLock.swift in Sources */, - 30E0289934EEBBB76CBEC3063F461F86 /* RecursiveScheduler.swift in Sources */, - 473F1C89DF4F981A9231DA64B7959E75 /* Reduce.swift in Sources */, - 5F613B97C5A9FB68E45744D3708AAE25 /* RefCountDisposable.swift in Sources */, - 20588EFAFB30DD4317FB2EDA75B0DECE /* Repeat.swift in Sources */, - 4FC9E9B4D558C89C8EF7144529E26449 /* ReplaySubject.swift in Sources */, - 41752621D36551F16F12C44CEE1F5166 /* RetryWhen.swift in Sources */, - FE460145756A99E48821E2C77787C8E2 /* Rx.swift in Sources */, - 59BA69203E1EAD6065517250EBC344AF /* RxMutableBox.swift in Sources */, - 23B9CAC8AD17E0E048E75732BA9CB675 /* RxSwift-dummy.m in Sources */, - C506645305BAAB18BD37A354C03CCECD /* Sample.swift in Sources */, - 08D08714BCF5A3CA12200BF3A22B1C86 /* Scan.swift in Sources */, - 4441C02A32D1D469F208A5925BE92467 /* ScheduledDisposable.swift in Sources */, - 0E6FA44DD92DFE1EC8636DFDD664E9F5 /* ScheduledItem.swift in Sources */, - 549DA3825EF92864B1FA9FFCF99F2537 /* ScheduledItemType.swift in Sources */, - 3AAFB9CC4F818A8B787A6B77464B18C7 /* SchedulerServices+Emulation.swift in Sources */, - C02096C50B5EC4D188E0DA02905257AE /* SchedulerType.swift in Sources */, - C30F1E1AB8A93311FE04381989A8CEFE /* Sequence.swift in Sources */, - 154A08CBAA75B8111A87BA7F637F41AA /* SerialDispatchQueueScheduler.swift in Sources */, - 0E1F1CA0797B529C2CAC2956CA1F3DDD /* SerialDisposable.swift in Sources */, - 466E1FA9DC6F99B0C6B6B5F4251FDF47 /* ShareReplayScope.swift in Sources */, - 1791390AD93AB8419131459DF03800DF /* Single.swift in Sources */, - 6ABE5C6E5B9C3F361B716B482E174666 /* SingleAssignmentDisposable.swift in Sources */, - CB817941DDB243A69908CEF658DB7FE2 /* SingleAsync.swift in Sources */, - EB62DF6C85B2E9027282E1E11A0B9E9F /* Sink.swift in Sources */, - 8CA954A1E8DDAC844F88DA711D66FDF7 /* Skip.swift in Sources */, - FE25BB49532E0DA3A59980FCA28F4303 /* SkipUntil.swift in Sources */, - 4362AA421B2EE7A28A3731E7ECED59A6 /* SkipWhile.swift in Sources */, - 4D4C9A22FE30B0D37DB1D283D1B6A804 /* StartWith.swift in Sources */, - D9831CF6644519EA56FC7D1AD87D0E86 /* SubjectType.swift in Sources */, - C29F61C558148A9A7401DB6AF57FF214 /* SubscribeOn.swift in Sources */, - 779270736284A8CA1DB0BE207D806535 /* SubscriptionDisposable.swift in Sources */, - 85C215D20BE5E66A0D4F7A8E6E1438BA /* SwiftSupport.swift in Sources */, - F25C3C6D98039FCE6A01CB7484AD9D1B /* Switch.swift in Sources */, - 645B4FEB58991182E0EDAC1D3E694247 /* SwitchIfEmpty.swift in Sources */, - 7252D3B557D3BF17CBAAC5B6878A18DF /* SynchronizedDisposeType.swift in Sources */, - 2F336C33B921805B1B5E49EC63BFCD68 /* SynchronizedOnType.swift in Sources */, - 5F653960E8C236643ADE4D33DC6B987C /* SynchronizedUnsubscribeType.swift in Sources */, - 307CAB3C89EA02A51CDD5C11A4EDE036 /* TailRecursiveSink.swift in Sources */, - 43C88503368D2779C7C7F8B203AFA34F /* Take.swift in Sources */, - A001F99FC48A2CB820E977146AE31F54 /* TakeLast.swift in Sources */, - CDED4A952693B2BD16556F11FE171FF3 /* TakeWithPredicate.swift in Sources */, - 270C6886BAA3FC9C18D0DF59F6B164FD /* Throttle.swift in Sources */, - 553950D2C5D7058D7F6AC96C3F508060 /* Timeout.swift in Sources */, - 4645C8DB11FE2FA7836124E77A768650 /* Timer.swift in Sources */, - F63FD0F0533CAE100F1F547635F40301 /* ToArray.swift in Sources */, - ED672A89F65EF876A81E3D7384E7BB1A /* Using.swift in Sources */, - C50EFF96E2BB35B40F02BFFC7624791F /* VirtualTimeConverterType.swift in Sources */, - 12A74636E7AE8263F9F9968EA2BBC7C0 /* VirtualTimeScheduler.swift in Sources */, - 447A2D4A1D0162C87280DF7C59E9FA29 /* Window.swift in Sources */, - 0CA6ED2C33BC2AE8CF0DBC5EBF997E26 /* WithLatestFrom.swift in Sources */, - 33178EB30F3F079DB41FEDE82E7C331C /* WithUnretained.swift in Sources */, - F2555054E054DE4B977C72D31968B020 /* Zip.swift in Sources */, - 08B6CF630CFB353341DC145F9260B8A6 /* Zip+arity.swift in Sources */, - 6468B3694ABBC835D9FE3CA6F2BA44B9 /* Zip+Collection.swift in Sources */, + 966FD99CF015E0E1DE82724BEBAF6F47 /* BehaviorRelay.swift in Sources */, + C66AB81E05FBA6BA810072DEB7D45EE5 /* Observable+Bind.swift in Sources */, + 28AC98B2CADD31F0868D4AF4979E9FD2 /* PublishRelay.swift in Sources */, + 258C51B954DEA64AD604A62BDE522842 /* ReplayRelay.swift in Sources */, + A09269702D45FA71B146BBDE37571325 /* RxRelay-dummy.m in Sources */, + 2BC5CE923B1642BD1D819DF33B4B3710 /* Utils.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - B91D9451C23913E7C8A6B25EB289F975 /* Sources */ = { + E655BC65A74D7C39E79FB3C492044353 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - CB14BA773C9A13976D90006D9A843379 /* Pods-Instagram-Clone-dummy.m in Sources */, + 7016FD62B55A814DB246B3286CEB44A2 /* AddRef.swift in Sources */, + 93E36BBF7E4EA867F3301D79C1BC378E /* Amb.swift in Sources */, + 5FF9F855ABBFE05AD568D40398E8790D /* AnonymousDisposable.swift in Sources */, + CFCC48239D82DEAB7B3541A59C7F439D /* AnonymousObserver.swift in Sources */, + 2C6ABD95B263C08BA54FD26E7EDFECE1 /* AnyObserver.swift in Sources */, + 3EC3D62A64883A9AE11396EB7C84206E /* AsMaybe.swift in Sources */, + 044B3C2F907BA92CE4BD757722963384 /* AsSingle.swift in Sources */, + 6466998AAB36640368F482091316EBF6 /* AsyncLock.swift in Sources */, + 8540FFA5EAC0F99F641A2F0D4C164917 /* AsyncSubject.swift in Sources */, + 898842972F3799802AAB201F84B8CA39 /* AtomicInt.swift in Sources */, + 3685C88CA5F36F4170E84DD0227D244A /* Bag.swift in Sources */, + B3621037B1B0E697C854F0FF109A594C /* Bag+Rx.swift in Sources */, + 9166043CED65CDD457AF559A9B127E17 /* BehaviorSubject.swift in Sources */, + 2B82281C44FE73DE8D962123E0DB9587 /* BinaryDisposable.swift in Sources */, + A3330962182718216DA19E8F8F5C585C /* Binder.swift in Sources */, + 847EBE58CCA654734197C7384E7B4094 /* BooleanDisposable.swift in Sources */, + A842C160BF51636979E2364404DF3E30 /* Buffer.swift in Sources */, + 893252F553C133D865FA1BD98D08881F /* Cancelable.swift in Sources */, + 9F497DACD3A261A4940D09D7A68C8C8C /* Catch.swift in Sources */, + 7024A2E9D2A76033F9F524AD94256D55 /* CombineLatest.swift in Sources */, + B6D19CD2E68222A070CE0EB061FC4604 /* CombineLatest+arity.swift in Sources */, + 078C84CF59337DA8762F8C633AB70E54 /* CombineLatest+Collection.swift in Sources */, + B25714FEA238E63EFCC45BF5646864B6 /* CompactMap.swift in Sources */, + 963BD25D8D11DE9D03732937C7CA5FB3 /* Completable.swift in Sources */, + CA38E66DD2A16B2C3BF0B871AE215D6B /* Completable+AndThen.swift in Sources */, + 3440AB5A3A26F7706143726E7B6CFD41 /* CompositeDisposable.swift in Sources */, + F0BF3B6C0494A86881130807FC9896FF /* Concat.swift in Sources */, + 11FC6A5EEDB9F31A8BB02ABBDF67CC4D /* ConcurrentDispatchQueueScheduler.swift in Sources */, + 81095C6CBB8956AF79E33BCE939AFC2D /* ConcurrentMainScheduler.swift in Sources */, + 2804E6D768D9F7A9A4D0DFA9C4C947CD /* ConnectableObservableType.swift in Sources */, + 1E95C7EABB9F919C737C4572CF01E9CA /* Create.swift in Sources */, + 2D7A33D35011E2763FF5650BCE8705C0 /* CurrentThreadScheduler.swift in Sources */, + B6B0D29695B41D7265D9DE7E1D154405 /* Date+Dispatch.swift in Sources */, + C476A90BE4CFB2515507AC4B72DCB36B /* Debounce.swift in Sources */, + F99CF4A8FDB51B0EB05DFD968E9EDE46 /* Debug.swift in Sources */, + D12C55FCA09B4EDB39F53C873CC9CA47 /* Decode.swift in Sources */, + 3F16037EF959D92481B4E5CAB91983A2 /* DefaultIfEmpty.swift in Sources */, + CAD49B3D93412E69BE3DADA23B31941A /* Deferred.swift in Sources */, + 35F188D95219806671DFF0A26805E7EE /* Delay.swift in Sources */, + 3496CF128687DF8E8649A8BA79C923D4 /* DelaySubscription.swift in Sources */, + 7D5C429450288B43FFDE26CFDD7BECB2 /* Dematerialize.swift in Sources */, + 23D26111AAAA97350CE0A0C0B9A66823 /* DispatchQueue+Extensions.swift in Sources */, + 3BDE15405AF6942A6BDFBC25EC869206 /* DispatchQueueConfiguration.swift in Sources */, + 522A41C059E5B3C6C02DF4A3C2E4511E /* Disposable.swift in Sources */, + F28CBBA286F282A892A5B564282BDDC9 /* Disposables.swift in Sources */, + 26DDC1A34DD94CA11120FD2EC22FFE4D /* DisposeBag.swift in Sources */, + 2A76C0C87BECC7444FA23FE5FF39A487 /* DisposeBase.swift in Sources */, + 120765129F415ACB32122F4F5773E494 /* DistinctUntilChanged.swift in Sources */, + C0DCA1EC7FD3E2AB3023238F1DAEF1C2 /* Do.swift in Sources */, + B427A8E277EDF230990C4E6BFB0896B3 /* ElementAt.swift in Sources */, + 442F99A1D4DBDCC3EE4D650936065479 /* Empty.swift in Sources */, + 57168D708E9521362A4F4B59AD82FB1C /* Enumerated.swift in Sources */, + 4B9E089D03AB2A9FEDE3B25BBAE206CE /* Error.swift in Sources */, + FCCB571EBE4AF1A4FBA44A16AEF28526 /* Errors.swift in Sources */, + AF745E785C247AA2081CEF2C52643BB3 /* Event.swift in Sources */, + 7CE78060DC2CC6D444FBE6966914134C /* Filter.swift in Sources */, + 17E407500F471F7253C1EBBE28BABC25 /* First.swift in Sources */, + FA6537309E3B7A21A83E00774305275F /* Generate.swift in Sources */, + 5650EE6C7E606AE6BF10761F90BB045C /* GroupBy.swift in Sources */, + A00B02753121E48F19A40E0AA234F27F /* GroupedObservable.swift in Sources */, + 90E87249660F4D3321E01F0F075095CC /* HistoricalScheduler.swift in Sources */, + 26043B9FF33DCA7D59F1DCDBD425F2E3 /* HistoricalSchedulerTimeConverter.swift in Sources */, + 185D79F9660F74FE0DDAF3EE71098AE5 /* ImmediateSchedulerType.swift in Sources */, + F564D07AA19C49E882A68963914E55AA /* Infallible.swift in Sources */, + C9FBDF5C0881490E629EACD2928ADF11 /* Infallible+CombineLatest+arity.swift in Sources */, + 775B8F8F47D2D5F672D39D51ED962DDB /* Infallible+Create.swift in Sources */, + 2DD61C8CDBF0EC6C41F8484607616242 /* Infallible+Operators.swift in Sources */, + 3C456A929F009FB2A87D084E6A04D227 /* Infallible+Zip+arity.swift in Sources */, + ADC81CC0E59F09E172453DF440E97103 /* InfiniteSequence.swift in Sources */, + B7B2D2BA017F31692A03052861B7A5B3 /* InvocableScheduledItem.swift in Sources */, + B53CC742CD11968434A0A63B176A8FF6 /* InvocableType.swift in Sources */, + D3FEDFC5BAE7D0A94414C4230E2B363E /* Just.swift in Sources */, + B4D195EF46872334B240F3DF7D52A2F4 /* Lock.swift in Sources */, + EB8FE24044E9093C48AADB3985FC7D43 /* LockOwnerType.swift in Sources */, + EBF6254441C10CCC5F8C919AF9A8E8CF /* MainScheduler.swift in Sources */, + C9FB700EA3EFA40792CC5E6344EA4A9A /* Map.swift in Sources */, + 9A658600907098820AE61B00B7A0FEA0 /* Materialize.swift in Sources */, + 7A243B952653A37D1AF93122D3BBCAFD /* Maybe.swift in Sources */, + 6604D3F29241ADE4132FB184EE7AC42A /* Merge.swift in Sources */, + 4DA69E2BBC485752A9DD91980A109765 /* Multicast.swift in Sources */, + 16A880061B451E53F8D83C75110D2E69 /* Never.swift in Sources */, + A35821CCB39160451DFA5C1E1D95D283 /* NopDisposable.swift in Sources */, + CA7E6313F023439E2D6C9801EB6202A7 /* Observable.swift in Sources */, + 5C43178561F518739BB1B49DA976DF7B /* ObservableConvertibleType.swift in Sources */, + 061EDABCC0367AF86ED8E40F3CE61BD4 /* ObservableConvertibleType+Infallible.swift in Sources */, + F6495BDDBBBB8B2B736175C1356622DF /* ObservableType.swift in Sources */, + B31C49F56A9C1CFAB698384FBBAC68AF /* ObservableType+Extensions.swift in Sources */, + 0CDDAC93C6BB582C0911153CC0C77713 /* ObservableType+PrimitiveSequence.swift in Sources */, + B9F08FA7D76F3520EC5AA58987532DD3 /* ObserveOn.swift in Sources */, + F78AA3DD00AAD9DFD92BECF4CC1EBAC0 /* ObserverBase.swift in Sources */, + 14D048F0762E69A25CBB773E84C1CDCE /* ObserverType.swift in Sources */, + 493127C2F29206E39BABF0F5EEBE3E66 /* OperationQueueScheduler.swift in Sources */, + B642FE050151439BD436A016549A5AFD /* Optional.swift in Sources */, + 08AE1EBFBBAB24BC410CA3DACF4C1100 /* Platform.Darwin.swift in Sources */, + 75A6FEB218DD9F07987C72818AAD4C95 /* Platform.Linux.swift in Sources */, + 08798AEC797123E25AFC88A5B1902455 /* PrimitiveSequence.swift in Sources */, + 089BEC9E0B7F904B3970C7713A1711E5 /* PrimitiveSequence+Zip+arity.swift in Sources */, + BE5B281805F9991E38CA52CC2E365CA8 /* PriorityQueue.swift in Sources */, + 900441C94889A5857E6A62ED130645E1 /* Producer.swift in Sources */, + 5CB7453A3225B8F762D666500654783F /* PublishSubject.swift in Sources */, + EBF094241C1849BB99B08D995A12DE50 /* Queue.swift in Sources */, + 468F4F96FF17FA2109E912945E6ADDD5 /* Range.swift in Sources */, + B0243071D95B74AE6520F5901A5C54E3 /* Reactive.swift in Sources */, + EA0EA1B249889B5FCCB81A987B1B3692 /* RecursiveLock.swift in Sources */, + 272399005DD92F08084869CB8C955A97 /* RecursiveScheduler.swift in Sources */, + C94188E1E8D5A6222FE10E1324FD7241 /* Reduce.swift in Sources */, + 11DDE893107A616B0CF871914526BB29 /* RefCountDisposable.swift in Sources */, + 594A8689EFB607611557F8BD05521C3B /* Repeat.swift in Sources */, + 350A88CD380253A5239CAA47B5C78EC7 /* ReplaySubject.swift in Sources */, + 2D05B426216B69D767ECB8145CE4B4E2 /* RetryWhen.swift in Sources */, + F0A8DBA0B324F3A63C8EF2DADB6FBF07 /* Rx.swift in Sources */, + 72EACA60D843947316E0D45FD074C744 /* RxMutableBox.swift in Sources */, + 8D351E59580B8F5EA4D1F1E9C926608F /* RxSwift-dummy.m in Sources */, + 397B37B379C8A6D905381B8F5E18F391 /* Sample.swift in Sources */, + 291212C7E7B0846DE4EE715CEE2D7A18 /* Scan.swift in Sources */, + E425FA08EAAE8E9961CC099844376D82 /* ScheduledDisposable.swift in Sources */, + 142A47FCA4C5D1BB72B039C574ED50A7 /* ScheduledItem.swift in Sources */, + A1A1FF8C15D79B3C9ED0121FE1642000 /* ScheduledItemType.swift in Sources */, + F0DC64268DD8A00793B71880D8A8124D /* SchedulerServices+Emulation.swift in Sources */, + CA0C80FE14246281AF85FA8898C5D7BA /* SchedulerType.swift in Sources */, + 9872BA71E352EE554FB705FBCDAA3C40 /* Sequence.swift in Sources */, + CD67D7019DCA2D8C5AA2842C0E0BD695 /* SerialDispatchQueueScheduler.swift in Sources */, + DE57D4F4A5577B90D3AE5CFEAB0386B9 /* SerialDisposable.swift in Sources */, + C6272C72012F7E61389660D757E69377 /* ShareReplayScope.swift in Sources */, + E4AB81BD6C225C98E39A8A81062485E8 /* Single.swift in Sources */, + 5B58B8650A9AE15A40EA145EBFBD4FE5 /* SingleAssignmentDisposable.swift in Sources */, + 5A6440D152055824959434874F2D583C /* SingleAsync.swift in Sources */, + 0D56320304D2381978200C77A901F12F /* Sink.swift in Sources */, + B87E54A6A887700FD31379C0C6AE709C /* Skip.swift in Sources */, + 532A9D1C9C53318F736994B5DA9AA3A3 /* SkipUntil.swift in Sources */, + DF13840B7938888650B19F8D844DB422 /* SkipWhile.swift in Sources */, + 0AC9B1295F073079750B00AA0E6C9CBF /* StartWith.swift in Sources */, + 742C6177ED8662FF241782BA7334E634 /* SubjectType.swift in Sources */, + E3C48387BE80334EA28DBB3F73ADA592 /* SubscribeOn.swift in Sources */, + F90BC71185AD63D583158C6F59992359 /* SubscriptionDisposable.swift in Sources */, + E352E97B987205D92E23CE464271278E /* SwiftSupport.swift in Sources */, + 11612E8356B8DEAD493E031966EB7E1A /* Switch.swift in Sources */, + C4D3565A73D43F43B237AA3B63730B5C /* SwitchIfEmpty.swift in Sources */, + A32E5E2F188BE43B5A81403FD909D832 /* SynchronizedDisposeType.swift in Sources */, + 134FD4E988EB8113AD19EAD10F2B07E9 /* SynchronizedOnType.swift in Sources */, + AEED75FDE3F814DF658D2F7814968377 /* SynchronizedUnsubscribeType.swift in Sources */, + B1C0A51154B2C73747A94C776622B414 /* TailRecursiveSink.swift in Sources */, + 4978F4A7A4B4ABC4A51E9F54FF6E45A9 /* Take.swift in Sources */, + 6CA34295D3627D8159E4CB8C18DEEFF9 /* TakeLast.swift in Sources */, + 9881194F4BA84B4F860B816C911C90FE /* TakeWithPredicate.swift in Sources */, + 4718D5DB01C595629D6E05136B3ECC88 /* Throttle.swift in Sources */, + 5406B893BC83767F08861921012B4659 /* Timeout.swift in Sources */, + 71D5D19E7A964BCDC00D217AAC6C6E4D /* Timer.swift in Sources */, + BA2A348ADCA09F37B08F8C354CB4363A /* ToArray.swift in Sources */, + 04B947DDBCF65286F1CD57A50F0F8E82 /* Using.swift in Sources */, + D5B24C3951015F77332C0119C80F312F /* VirtualTimeConverterType.swift in Sources */, + 1E45F13782B6B44884328DC493C1CB26 /* VirtualTimeScheduler.swift in Sources */, + F5F07074DA7197374955965C99B49DE3 /* Window.swift in Sources */, + 2A14C75617DF21ED981690C05AED614E /* WithLatestFrom.swift in Sources */, + DC17EB814ABCAF1ABEA2F1627752866B /* WithUnretained.swift in Sources */, + 77319AE6A71B95F2B926B55B5C264F77 /* Zip.swift in Sources */, + E6F9EC2C837AEAD6CB9EAAB1EC05661F /* Zip+arity.swift in Sources */, + 420C68A3D27F8DE314301669960F66D2 /* Zip+Collection.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; - DE80953551E4BA26C461B657192C6F1B /* Sources */ = { + F15AD905B04CC8E3EC976C8D01C24366 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 05D0DB0B68BD602E6AF8C2A9B938A2B5 /* BehaviorRelay.swift in Sources */, - 27D5E789967F99EE82FADEAD73D83459 /* Observable+Bind.swift in Sources */, - A56CD1D3422F2829C360685A02D7A9AB /* PublishRelay.swift in Sources */, - 5999CC5A3F84BD421AE116E29F47B83D /* ReplayRelay.swift in Sources */, - AE699CB7ACA4FD73BB4D02A856683B76 /* RxRelay-dummy.m in Sources */, - 48B27B6A17D7EABB0246EB78751E67AF /* Utils.swift in Sources */, + 21B7E9948690429E1F56EDA38B717A2C /* Pods-Instagram-Clone-dummy.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1623,55 +1822,105 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + F5D2A45FBA06D86A537CB441D5BF4FF4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D0EA90FBF83350C49E6EF6C8A98D6F00 /* AFError.swift in Sources */, + F17A4CA4664CABB331D39FE902E06843 /* Alamofire.swift in Sources */, + 55AABB1FB38F61A3369ACC555FF3046D /* Alamofire-dummy.m in Sources */, + 1EE44196E7BCE57AD96A2C751651EF40 /* AlamofireExtended.swift in Sources */, + 7483E5327027263F7E4B94A2997191C4 /* AuthenticationInterceptor.swift in Sources */, + 2CBE3651CA006E19F5D64A2DE9B9A028 /* CachedResponseHandler.swift in Sources */, + 46A64A43AFA057B6B63C8F0C12F509B4 /* Combine.swift in Sources */, + 9C9030DEDB0DF955B16FE08C50892D57 /* Concurrency.swift in Sources */, + EEC150B66BCCD6C80FDA7E4D1975166B /* DispatchQueue+Alamofire.swift in Sources */, + CEBFFEED65D877702B2F36102528CF6D /* EventMonitor.swift in Sources */, + 7E02F5B62BE00E97847DF549FFED2490 /* HTTPHeaders.swift in Sources */, + D6B4751CED01D53E4A1B6A571AAA2F83 /* HTTPMethod.swift in Sources */, + 7FE695DA8EE7FF1286556E06B692009B /* MultipartFormData.swift in Sources */, + E9B4C89E7EB3B27D46AFCA452C3D426F /* MultipartUpload.swift in Sources */, + A29100AA1876DDEFF6F54694A51FDB0E /* NetworkReachabilityManager.swift in Sources */, + 2CCD13099063CD560E3067BD132914FA /* Notifications.swift in Sources */, + E54654D504A42C24F284A68F87F7671D /* OperationQueue+Alamofire.swift in Sources */, + 99D058E53EFEE3AC4857CDE3DBA5C004 /* ParameterEncoder.swift in Sources */, + 68FB2DCB4C77DBCAF9A6037E470F2BDE /* ParameterEncoding.swift in Sources */, + A53BDE589BDD6483F3EEDCE5EA1DCCD3 /* Protected.swift in Sources */, + 045DE6EBF9B2F63F60F5BE60C1198E06 /* RedirectHandler.swift in Sources */, + B3658C29BBDE1033F6269A92E612CB30 /* Request.swift in Sources */, + DD902FE8D6824681C929D028655AE121 /* RequestInterceptor.swift in Sources */, + DA34899BEF0668D76CBCE8C4CE47B97B /* RequestTaskMap.swift in Sources */, + 75966A9262648D4647D764E3E76BC6AC /* Response.swift in Sources */, + 824D816B1EE404F2DD400EE678695CBE /* ResponseSerialization.swift in Sources */, + 04A896288CE3A59B530250337A5F8362 /* Result+Alamofire.swift in Sources */, + 33A7D0F2D03004CE256A75E03DF33C70 /* RetryPolicy.swift in Sources */, + B704B198B9B520D449260877E300D821 /* ServerTrustEvaluation.swift in Sources */, + 81B8D2B7CEB25C2448B0BC9B33591A65 /* Session.swift in Sources */, + 1976BB7D7E26A12E29283E71154B63B3 /* SessionDelegate.swift in Sources */, + 7F1BB526AAE3ECDCE90127D9D0E10261 /* StringEncoding+Alamofire.swift in Sources */, + 8D75FC8D7476C9674234F39F1A820D8C /* URLConvertible+URLRequestConvertible.swift in Sources */, + 7930C94414B4C661867AC4FBE82E996C /* URLEncodedFormEncoder.swift in Sources */, + BC0ECA8F22DEDE8886E189CD0EAA1197 /* URLRequest+Alamofire.swift in Sources */, + 808C960C82D708FC1A42C581D6CB4940 /* URLSessionConfiguration+Alamofire.swift in Sources */, + 3C4059621E23842C19D4EB5D35B41989 /* Validation.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 35C8021D50D8ADD21B141371B6A5EE80 /* PBXTargetDependency */ = { + 1174C85B4B0A901D4393B200578B159D /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = RxCocoa; - target = 7AD0C6DCDC9CEC8A3C7C10C7FEE07BE6 /* RxCocoa */; - targetProxy = A078FC00AD08CB78D3CEA95F1333F107 /* PBXContainerItemProxy */; + name = RxSwift; + target = EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */; + targetProxy = 8497A3C1D0917E4CBC7084CF881F0B7E /* PBXContainerItemProxy */; }; - 3D152496571B94A07486C3AB5F2B891E /* PBXTargetDependency */ = { + 1DDAA5965B14DE1774117F7962FD9B72 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = RxRelay; - target = 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */; - targetProxy = E53CE103361C949B39AA14128D342165 /* PBXContainerItemProxy */; + name = RxCocoa; + target = 7AD0C6DCDC9CEC8A3C7C10C7FEE07BE6 /* RxCocoa */; + targetProxy = D64A74A50369D956BF1AB44709E4F388 /* PBXContainerItemProxy */; }; - 7C69B27CCBBAF437804D9913D4D7C73B /* PBXTargetDependency */ = { + 55DBD1FAD1E1ED3D72B3EC75692FAD30 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = RxSwift; target = EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */; - targetProxy = B1166BCF0F179451C7AED96AA3B51248 /* PBXContainerItemProxy */; + targetProxy = B61E5B448C60F66FAD91B55ECACE7930 /* PBXContainerItemProxy */; }; - C0F11143C2946D639E3E3882511F4AEE /* PBXTargetDependency */ = { + 81E18313172EB5F74DD64716D0BA62A9 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = RxSwift; - target = EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */; - targetProxy = 6E7213C929FE071F443403901BDF4ABB /* PBXContainerItemProxy */; + name = RxRelay; + target = 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */; + targetProxy = 98D1137759F9EF8EC531CB21569DB4BA /* PBXContainerItemProxy */; }; - C9AC0C2C7C9F1F1D1A3594F0245B2E54 /* PBXTargetDependency */ = { + B9F3F03975FF54333708135C0DDE0C08 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - name = SwiftLint; - target = 52B60EC2A583F24ACBB69C113F5488B9 /* SwiftLint */; - targetProxy = 15D50F26F457497597AF3B7759D57DA7 /* PBXContainerItemProxy */; + name = Alamofire; + target = EAAA1AD3A8A1B59AB91319EE40752C6D /* Alamofire */; + targetProxy = BA58DBBCD4416DD6F14156E1664F6154 /* PBXContainerItemProxy */; }; - D2771474175712AEFE74B4DED8CFFE59 /* PBXTargetDependency */ = { + C902207C970CE58DDCADC9925735DC92 /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = RxRelay; target = 4622BFEF3DC16E8BD15EEFC30D4D0084 /* RxRelay */; - targetProxy = 7D2B90F2E7CD87B00A9020B8BA08FBBA /* PBXContainerItemProxy */; + targetProxy = 0147A0EC0EC18E201C8F6907A31C7CE2 /* PBXContainerItemProxy */; + }; + E8DE41A08A694D2D3B024F9C97D7619D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = SwiftLint; + target = 52B60EC2A583F24ACBB69C113F5488B9 /* SwiftLint */; + targetProxy = 95F383542701BD428AC157C1BD3EE71D /* PBXContainerItemProxy */; }; - EC0D889F4042FDDC39349AC314078D0E /* PBXTargetDependency */ = { + FDECC8D7B9E662002E278A9B42D9EA9C /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = RxSwift; target = EA9EA43B3B503823EE36C60D9C8A865F /* RxSwift */; - targetProxy = E13393B041C7B09A9BAB70DF2B2E148A /* PBXContainerItemProxy */; + targetProxy = CB63475E57D3D58955B7466F4B2CBAB1 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 18B548AFC4880C90588400E89D300F53 /* Release */ = { + 3A6EB94E1EB1E97A87DA94F3405942CE /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 5A170BBCAFF78F759B451CA2332B8CD9 /* Pods-Instagram-Clone.release.xcconfig */; buildSettings = { @@ -1709,9 +1958,44 @@ }; name = Release; }; - 5C825BE17456CD974CE6A01C6D13A131 /* Release */ = { + 3AF96EF929F18B4959DCFBF1E86A84D7 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7E8F125BC91320E99EBE78FEE1309CDA /* RxRelay.release.xcconfig */; + baseConfigurationReference = 4B9AA9F85FB7028720BC48147A7340E8 /* RxSwift.release.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RxSwift/RxSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RxSwift/RxSwift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RxSwift/RxSwift.modulemap"; + PRODUCT_MODULE_NAME = RxSwift; + PRODUCT_NAME = RxSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.1; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 71B59C8AFA63855091899980CA82F9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FD6E426F20C80EA25A69B8D17C2C9DFB /* RxRelay.release.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -1744,9 +2028,43 @@ }; name = Release; }; + 76FC60FDD9C57DB2E9154328165AE369 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 363A4B179A004E5C46D5AEDEEFD28431 /* RxSwift.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RxSwift/RxSwift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RxSwift/RxSwift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RxSwift/RxSwift.modulemap"; + PRODUCT_MODULE_NAME = RxSwift; + PRODUCT_NAME = RxSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.1; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; 7D34C1F5EEAF808252A41D4904D30039 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 42E8C86A17D8344F4AFE300FDA80AB49 /* RxCocoa.debug.xcconfig */; + baseConfigurationReference = 5B6CB2FCC481D092A24CD0A922397325 /* RxCocoa.debug.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -1778,6 +2096,76 @@ }; name = Debug; }; + 8EABCCB5809BE80BC470AE6732EF3777 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0409B4163021C318D05F2A0F97350868 /* RxRelay.debug.xcconfig */; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/RxRelay/RxRelay-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/RxRelay/RxRelay-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/RxRelay/RxRelay.modulemap"; + PRODUCT_MODULE_NAME = RxRelay; + PRODUCT_NAME = RxRelay; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.1; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 90A4588B06F8745E7FCD1B00204D6241 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0AD7897AC94CD3CD139D7249BCBA09AA /* Alamofire.release.xcconfig */; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; + "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREFIX_HEADER = "Target Support Files/Alamofire/Alamofire-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Alamofire/Alamofire-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MODULEMAP_FILE = "Target Support Files/Alamofire/Alamofire.modulemap"; + PRODUCT_MODULE_NAME = Alamofire; + PRODUCT_NAME = Alamofire; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.5; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; 90D4D09BCB6A4660E43ACBE9ECB6FE9A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1908,7 +2296,7 @@ }; 96859D0CBA06C4EA7691E92BBFBE3F95 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9AE802EE93AC891F8BBD3595F4F97123 /* RxCocoa.release.xcconfig */; + baseConfigurationReference = 89DE6A4A58CC9CBDADB822DD004594A0 /* RxCocoa.release.xcconfig */; buildSettings = { "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; @@ -1941,10 +2329,11 @@ }; name = Release; }; - 9B478F52112FB79E6A54E1CCAFA9E94B /* Release */ = { + 9E98C04A5FA16D8AD5D48C1861179497 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9E98442EE02EEDF78B15D2F6A5168DDA /* RxSwift.release.xcconfig */; + baseConfigurationReference = A360A1E748495A656A23264F856CCF30 /* Alamofire.debug.xcconfig */; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = NO; "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; @@ -1953,32 +2342,31 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/RxSwift/RxSwift-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/RxSwift/RxSwift-Info.plist"; + GCC_PREFIX_HEADER = "Target Support Files/Alamofire/Alamofire-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Alamofire/Alamofire-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/RxSwift/RxSwift.modulemap"; - PRODUCT_MODULE_NAME = RxSwift; - PRODUCT_NAME = RxSwift; + MODULEMAP_FILE = "Target Support Files/Alamofire/Alamofire.modulemap"; + PRODUCT_MODULE_NAME = Alamofire; + PRODUCT_NAME = Alamofire; SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.1; + SWIFT_VERSION = 5.5; TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; - name = Release; + name = Debug; }; AD81E62ACCB0B7A923FC8AA288F9921E /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7E5A11BFD4B2349FE0800D0FEE107B6E /* SwiftLint.release.xcconfig */; + baseConfigurationReference = 2A06AA26688719BE78A832A68E8139C0 /* SwiftLint.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; @@ -1993,75 +2381,23 @@ }; name = Release; }; - BBFE8D54C7F3B6052DD33FB8377CED95 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 24701C2CDA783D537E98D65A2919ADBB /* RxRelay.debug.xcconfig */; - buildSettings = { - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/RxRelay/RxRelay-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/RxRelay/RxRelay-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MODULEMAP_FILE = "Target Support Files/RxRelay/RxRelay.modulemap"; - PRODUCT_MODULE_NAME = RxRelay; - PRODUCT_NAME = RxRelay; - SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.1; - TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - C7EBBEDA6CB4BA098451AFA3F93071F8 /* Debug */ = { + EADD1F50ABC8096A0D6CB18822BB4EE4 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = AF77625DB712A38BD99168A49606C55F /* RxSwift.debug.xcconfig */; + baseConfigurationReference = 29E0682772F7E3BF82479D100F042D2A /* SwiftLint.debug.xcconfig */; buildSettings = { - "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - GCC_PREFIX_HEADER = "Target Support Files/RxSwift/RxSwift-prefix.pch"; - INFOPLIST_FILE = "Target Support Files/RxSwift/RxSwift-Info.plist"; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", - "@loader_path/Frameworks", ); - MODULEMAP_FILE = "Target Support Files/RxSwift/RxSwift.modulemap"; - PRODUCT_MODULE_NAME = RxSwift; - PRODUCT_NAME = RxSwift; SDKROOT = iphoneos; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 5.1; TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; }; name = Debug; }; - E04E4A8F4A95A7F8B240E85BE62EA3AD /* Debug */ = { + FAA6726CE845669F75036E108D9A9845 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 832600334A0B039D6270E3CE9FDCF8F8 /* Pods-Instagram-Clone.debug.xcconfig */; buildSettings = { @@ -2098,22 +2434,6 @@ }; name = Debug; }; - EADD1F50ABC8096A0D6CB18822BB4EE4 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 6C867006979B630B992855A4332250EA /* SwiftLint.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -2126,6 +2446,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 379E8A1260B94A013AE0116EF9119546 /* Build configuration list for PBXNativeTarget "Pods-Instagram-Clone" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FAA6726CE845669F75036E108D9A9845 /* Debug */, + 3A6EB94E1EB1E97A87DA94F3405942CE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -2135,20 +2464,20 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 6F222468B6B50703AAA3B9D52DF18D03 /* Build configuration list for PBXNativeTarget "Pods-Instagram-Clone" */ = { + 5CA471FA9BA4D8AEB61463D4594FF33D /* Build configuration list for PBXNativeTarget "RxRelay" */ = { isa = XCConfigurationList; buildConfigurations = ( - E04E4A8F4A95A7F8B240E85BE62EA3AD /* Debug */, - 18B548AFC4880C90588400E89D300F53 /* Release */, + 8EABCCB5809BE80BC470AE6732EF3777 /* Debug */, + 71B59C8AFA63855091899980CA82F9CD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 8055F1D78688E5422827AD5F695641D5 /* Build configuration list for PBXNativeTarget "RxSwift" */ = { + 8A212264186B8822192F9C369D7DE4BB /* Build configuration list for PBXNativeTarget "Alamofire" */ = { isa = XCConfigurationList; buildConfigurations = ( - C7EBBEDA6CB4BA098451AFA3F93071F8 /* Debug */, - 9B478F52112FB79E6A54E1CCAFA9E94B /* Release */, + 9E98C04A5FA16D8AD5D48C1861179497 /* Debug */, + 90A4588B06F8745E7FCD1B00204D6241 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -2162,11 +2491,11 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - D36ADE6C0C851C68584DBA4B11D3F818 /* Build configuration list for PBXNativeTarget "RxRelay" */ = { + CE9D24514F4FD09A1AB2DFBBD2E4AFE6 /* Build configuration list for PBXNativeTarget "RxSwift" */ = { isa = XCConfigurationList; buildConfigurations = ( - BBFE8D54C7F3B6052DD33FB8377CED95 /* Debug */, - 5C825BE17456CD974CE6A01C6D13A131 /* Release */, + 76FC60FDD9C57DB2E9154328165AE369 /* Debug */, + 3AF96EF929F18B4959DCFBF1E86A84D7 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-Info.plist b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-Info.plist new file mode 100644 index 0000000..0c02b2a --- /dev/null +++ b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 5.5.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-dummy.m b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-dummy.m new file mode 100644 index 0000000..a6c4594 --- /dev/null +++ b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Alamofire : NSObject +@end +@implementation PodsDummy_Alamofire +@end diff --git a/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-prefix.pch b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-umbrella.h b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-umbrella.h new file mode 100644 index 0000000..00014e3 --- /dev/null +++ b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double AlamofireVersionNumber; +FOUNDATION_EXPORT const unsigned char AlamofireVersionString[]; + diff --git a/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.debug.xcconfig b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.debug.xcconfig new file mode 100644 index 0000000..7d169c4 --- /dev/null +++ b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.debug.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.modulemap b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.modulemap new file mode 100644 index 0000000..d1f125f --- /dev/null +++ b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.modulemap @@ -0,0 +1,6 @@ +framework module Alamofire { + umbrella header "Alamofire-umbrella.h" + + export * + module * { export * } +} diff --git a/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.release.xcconfig b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.release.xcconfig new file mode 100644 index 0000000..7d169c4 --- /dev/null +++ b/Instagram-Clone/Pods/Target Support Files/Alamofire/Alamofire.release.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "CFNetwork" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-acknowledgements.markdown b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-acknowledgements.markdown index 5c01256..1da7551 100644 --- a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-acknowledgements.markdown +++ b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-acknowledgements.markdown @@ -1,6 +1,29 @@ # Acknowledgements This application makes use of the following third party libraries: +## Alamofire + +Copyright (c) 2014-2021 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. + + ## RxCocoa **The MIT License** diff --git a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-acknowledgements.plist b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-acknowledgements.plist index 55dfc3e..b44ba67 100644 --- a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-acknowledgements.plist +++ b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-acknowledgements.plist @@ -12,6 +12,35 @@ Type PSGroupSpecifier + + FooterText + Copyright (c) 2014-2021 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. + + License + MIT + Title + Alamofire + Type + PSGroupSpecifier + FooterText **The MIT License** diff --git a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Debug-input-files.xcfilelist b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Debug-input-files.xcfilelist index a1b2ac1..429c0a0 100644 --- a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Debug-input-files.xcfilelist +++ b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Debug-input-files.xcfilelist @@ -1,4 +1,5 @@ ${PODS_ROOT}/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks.sh +${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework ${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework ${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework ${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework \ No newline at end of file diff --git a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Debug-output-files.xcfilelist b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Debug-output-files.xcfilelist index 050b788..612c254 100644 --- a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Debug-output-files.xcfilelist +++ b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Debug-output-files.xcfilelist @@ -1,3 +1,4 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxRelay.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework \ No newline at end of file diff --git a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Release-input-files.xcfilelist b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Release-input-files.xcfilelist index a1b2ac1..429c0a0 100644 --- a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Release-input-files.xcfilelist +++ b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Release-input-files.xcfilelist @@ -1,4 +1,5 @@ ${PODS_ROOT}/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks.sh +${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework ${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework ${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework ${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework \ No newline at end of file diff --git a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Release-output-files.xcfilelist b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Release-output-files.xcfilelist index 050b788..612c254 100644 --- a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Release-output-files.xcfilelist +++ b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks-Release-output-files.xcfilelist @@ -1,3 +1,4 @@ +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxRelay.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxSwift.framework \ No newline at end of file diff --git a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks.sh b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks.sh index 5781db6..b9fca35 100755 --- a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks.sh +++ b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone-frameworks.sh @@ -176,11 +176,13 @@ code_sign_if_enabled() { } if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework" install_framework "${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework" install_framework "${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework" install_framework "${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework" fi if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework" install_framework "${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework" install_framework "${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework" install_framework "${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework" diff --git a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.debug.xcconfig b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.debug.xcconfig index 9435f42..01f2c20 100644 --- a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.debug.xcconfig +++ b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.debug.xcconfig @@ -1,11 +1,11 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO -FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift -OTHER_LDFLAGS = $(inherited) -framework "RxCocoa" -framework "RxRelay" -framework "RxSwift" +OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CFNetwork" -framework "RxCocoa" -framework "RxRelay" -framework "RxSwift" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) diff --git a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.release.xcconfig b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.release.xcconfig index 9435f42..01f2c20 100644 --- a/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.release.xcconfig +++ b/Instagram-Clone/Pods/Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.release.xcconfig @@ -1,11 +1,11 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO -FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks' LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift -OTHER_LDFLAGS = $(inherited) -framework "RxCocoa" -framework "RxRelay" -framework "RxSwift" +OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CFNetwork" -framework "RxCocoa" -framework "RxRelay" -framework "RxSwift" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) From 8c257812ca4c4b2a7f3a421ed947fdf0d1248954 Mon Sep 17 00:00:00 2001 From: hyesuuou <68391767+hyesuuou@users.noreply.github.com> Date: Sun, 15 May 2022 13:46:36 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20#8=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Instagram-Clone.xcodeproj/project.pbxproj | 4 ++ .../Extensions/UIViewController+.swift | 25 ++++++++++++ .../Network/Base/GeneralResponse.swift | 7 ---- .../Network/Base/GeneralService.swift | 2 +- .../Network/Base/URLConstants.swift | 2 +- .../Network/Service/AuthService.swift | 8 +++- .../Auth/Signin/SigninViewController.swift | 39 +++++++++++++++++-- 7 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 Instagram-Clone/Instagram-Clone/Application/Extensions/UIViewController+.swift diff --git a/Instagram-Clone/Instagram-Clone.xcodeproj/project.pbxproj b/Instagram-Clone/Instagram-Clone.xcodeproj/project.pbxproj index ce0d6d4..5df0fbd 100644 --- a/Instagram-Clone/Instagram-Clone.xcodeproj/project.pbxproj +++ b/Instagram-Clone/Instagram-Clone.xcodeproj/project.pbxproj @@ -46,6 +46,7 @@ 15F0B95028309BE5008A300E /* NetworkConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B94F28309BE5008A300E /* NetworkConstants.swift */; }; 15F0B95228309C2C008A300E /* GeneralService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B95128309C2C008A300E /* GeneralService.swift */; }; 15F0B95428309C90008A300E /* AuthService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B95328309C90008A300E /* AuthService.swift */; }; + 15F0B9562830B6FF008A300E /* UIViewController+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15F0B9552830B6FF008A300E /* UIViewController+.swift */; }; 6B32C10577BFCF0CC42F4629 /* Pods_Instagram_Clone.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 541B2B5ED91686F41F07A0A8 /* Pods_Instagram_Clone.framework */; }; /* End PBXBuildFile section */ @@ -91,6 +92,7 @@ 15F0B94F28309BE5008A300E /* NetworkConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkConstants.swift; sourceTree = ""; }; 15F0B95128309C2C008A300E /* GeneralService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralService.swift; sourceTree = ""; }; 15F0B95328309C90008A300E /* AuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = ""; }; + 15F0B9552830B6FF008A300E /* UIViewController+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+.swift"; sourceTree = ""; }; 2FD571BBDA6B7266B6880E1A /* Pods-Instagram-Clone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Instagram-Clone.debug.xcconfig"; path = "Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.debug.xcconfig"; sourceTree = ""; }; 541B2B5ED91686F41F07A0A8 /* Pods_Instagram_Clone.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Instagram_Clone.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A9F2CFFA6199E7BEFAA4F976 /* Pods-Instagram-Clone.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Instagram-Clone.release.xcconfig"; path = "Target Support Files/Pods-Instagram-Clone/Pods-Instagram-Clone.release.xcconfig"; sourceTree = ""; }; @@ -152,6 +154,7 @@ isa = PBXGroup; children = ( 15858D942802A04200332653 /* UITextField+.swift */, + 15F0B9552830B6FF008A300E /* UIViewController+.swift */, ); path = Extensions; sourceTree = ""; @@ -538,6 +541,7 @@ 15858D562800B7BD00332653 /* InstagramSubtitleLabel.swift in Sources */, 15963F3627FF634A003C7A14 /* AppDelegate.swift in Sources */, 15963F7A2800AAF9003C7A14 /* BaseViewController.swift in Sources */, + 15F0B9562830B6FF008A300E /* UIViewController+.swift in Sources */, 15963F3827FF634A003C7A14 /* SceneDelegate.swift in Sources */, 15F0B94E2830996D008A300E /* GeneralResponse.swift in Sources */, 15963F652800A0D7003C7A14 /* SignupNameViewController.swift in Sources */, diff --git a/Instagram-Clone/Instagram-Clone/Application/Extensions/UIViewController+.swift b/Instagram-Clone/Instagram-Clone/Application/Extensions/UIViewController+.swift new file mode 100644 index 0000000..597b9af --- /dev/null +++ b/Instagram-Clone/Instagram-Clone/Application/Extensions/UIViewController+.swift @@ -0,0 +1,25 @@ +// +// UIViewController+.swift +// Instagram-Clone +// +// Created by 김혜수 on 2022/05/15. +// + +import UIKit + +extension UIViewController { + + func makeOKAlert(title: String, + message: String, + okAction: ((UIAlertAction) -> Void)? = nil, + completion: (() -> Void)? = nil) { + let alertViewController = UIAlertController(title: title, + message: message, + preferredStyle: .alert) + + let okAction = UIAlertAction(title: "확인", style: .default, handler: okAction) + alertViewController.addAction(okAction) + + self.present(alertViewController, animated: true, completion: completion) + } +} diff --git a/Instagram-Clone/Instagram-Clone/Network/Base/GeneralResponse.swift b/Instagram-Clone/Instagram-Clone/Network/Base/GeneralResponse.swift index 84609f0..309a6aa 100644 --- a/Instagram-Clone/Instagram-Clone/Network/Base/GeneralResponse.swift +++ b/Instagram-Clone/Instagram-Clone/Network/Base/GeneralResponse.swift @@ -13,13 +13,6 @@ struct GeneralResponse: Codable { var message: String? var data: T? - enum CodingKeys: String, CodingKey { - case message - case success - case data - case status - } - init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) message = (try? values.decode(String.self, forKey: .message)) ?? "" diff --git a/Instagram-Clone/Instagram-Clone/Network/Base/GeneralService.swift b/Instagram-Clone/Instagram-Clone/Network/Base/GeneralService.swift index e63c00c..0210917 100644 --- a/Instagram-Clone/Instagram-Clone/Network/Base/GeneralService.swift +++ b/Instagram-Clone/Instagram-Clone/Network/Base/GeneralService.swift @@ -9,7 +9,7 @@ import Foundation struct GeneralService { - static func judgeStatus(by statusCode: Int, _ data: Data, _ : T.Type) -> NetworkResult { + static func judgeStatus(by statusCode: Int, _ data: Data, _ type: T.Type) -> NetworkResult { let decoder = JSONDecoder() guard let decodedData = try? decoder.decode(GeneralResponse.self, from: data) else { return .pathErr } diff --git a/Instagram-Clone/Instagram-Clone/Network/Base/URLConstants.swift b/Instagram-Clone/Instagram-Clone/Network/Base/URLConstants.swift index b8d685a..022f608 100644 --- a/Instagram-Clone/Instagram-Clone/Network/Base/URLConstants.swift +++ b/Instagram-Clone/Instagram-Clone/Network/Base/URLConstants.swift @@ -9,7 +9,7 @@ import Foundation struct URLConstants { - static let baseURL = "http://13.124.62.236/" + static let baseURL = "http://13.124.62.236" static let authSignup = "/auth/signup" static let authSignin = "/auth/signin" diff --git a/Instagram-Clone/Instagram-Clone/Network/Service/AuthService.swift b/Instagram-Clone/Instagram-Clone/Network/Service/AuthService.swift index d0e5b7d..f3f52d6 100644 --- a/Instagram-Clone/Instagram-Clone/Network/Service/AuthService.swift +++ b/Instagram-Clone/Instagram-Clone/Network/Service/AuthService.swift @@ -22,7 +22,9 @@ struct AuthService { case.success(let data): let statusCode = res.response?.statusCode let data = data - let networkResult = GeneralService.judgeStatus(by: statusCode ?? 0, data, SigninResponse.self) + let networkResult = GeneralService.judgeStatus(by: statusCode ?? 0, + data, + SigninResponse.self) completion(networkResult) case .failure(let err): print(err) @@ -39,7 +41,9 @@ struct AuthService { case.success(let data): let statusCode = res.response?.statusCode let data = data - let networkResult = GeneralService.judgeStatus(by: statusCode ?? 0, data, SignupResponse.self) + let networkResult = GeneralService.judgeStatus(by: statusCode ?? 0, + data, + SignupResponse.self) completion(networkResult) case .failure(let err): print(err) diff --git a/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signin/SigninViewController.swift b/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signin/SigninViewController.swift index 5195fdd..6f21544 100644 --- a/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signin/SigninViewController.swift +++ b/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signin/SigninViewController.swift @@ -50,9 +50,7 @@ final class SigninViewController: BaseViewController, AuthProtocol { checkButtonEnable() } - // MARK: - IBAction - - @IBAction func signinButtonDidTap(_ sender: Any) { + private func goToAuthCompleteViewController() { guard let authCompleteViewController = UIStoryboard(name: Const.Storyboard.AuthComplete, bundle: nil) .instantiateViewController(withIdentifier: Const.ViewController.AuthCompleteViewController) as? AuthCompleteViewController else { return } authCompleteViewController.modalPresentationStyle = .fullScreen @@ -60,9 +58,44 @@ final class SigninViewController: BaseViewController, AuthProtocol { self.present(authCompleteViewController, animated: true, completion: nil) } + // MARK: - IBAction + + @IBAction func signinButtonDidTap(_ sender: Any) { + postSignin() + } + @IBAction func signupButtonDidTap(_ sender: Any) { guard let signupViewController = UIStoryboard(name: Const.Storyboard.Signup, bundle: nil) .instantiateViewController(withIdentifier: Const.ViewController.SignupNameViewController) as? SignupNameViewController else { return } self.navigationController?.pushViewController(signupViewController, animated: true) } } + +extension SigninViewController { + + func postSignin() { + guard let name = nameTextField.text, + let email = nameTextField.text, + let password = passwordTextField.text + else { return } + AuthService.shared.postSignin(user: AuthRequest(name: name, + email: email, + password: password)) { result in + switch result { + case .success: + self.makeOKAlert(title: "로그인 성공", + message: "로그인 성공했습니다.", + okAction: { _ in self.goToAuthCompleteViewController() }, + completion: nil) + case .requestErr: + self.makeOKAlert(title: "로그인 실패", message: "다시 로그인하세요", okAction: nil, completion: nil) + case .pathErr: + print("pathErr") + case .serverErr: + print("serverErr") + case .networkFail: + print("networkFail") + } + } + } +} From 4826c8a874dfa5128902a0ce3a894eff41486372 Mon Sep 17 00:00:00 2001 From: hyesuuou <68391767+hyesuuou@users.noreply.github.com> Date: Sun, 15 May 2022 13:55:45 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20#8=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Signup/SignupPasswordViewController.swift | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signup/SignupPasswordViewController.swift b/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signup/SignupPasswordViewController.swift index 6c6556f..2f4cbe6 100644 --- a/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signup/SignupPasswordViewController.swift +++ b/Instagram-Clone/Instagram-Clone/Presentation/Scenes/Auth/Signup/SignupPasswordViewController.swift @@ -43,6 +43,14 @@ final class SignupPasswordViewController: BaseViewController, AuthProtocol { self.navigationController?.popToRootViewController(animated: true) } + private func goToAuthCompleteViewController() { + guard let authCompleteViewController = UIStoryboard(name: Const.Storyboard.AuthComplete, bundle: nil) + .instantiateViewController(withIdentifier: Const.ViewController.AuthCompleteViewController) as? AuthCompleteViewController else { return } + authCompleteViewController.modalPresentationStyle = .fullScreen + authCompleteViewController.name = name ?? "" + self.present(authCompleteViewController, animated: true, completion: nil) + } + // MARK: - IBAction @IBAction func backButtonDidTap(_ sender: Any) { @@ -50,10 +58,34 @@ final class SignupPasswordViewController: BaseViewController, AuthProtocol { } @IBAction func nextButtonDidTap(_ sender: Any) { - guard let authCompleteViewController = UIStoryboard(name: Const.Storyboard.AuthComplete, bundle: nil) - .instantiateViewController(withIdentifier: Const.ViewController.AuthCompleteViewController) as? AuthCompleteViewController else { return } - authCompleteViewController.modalPresentationStyle = .fullScreen - authCompleteViewController.name = name ?? "" - self.present(authCompleteViewController, animated: true, completion: nil) + postSignup() + } +} + +extension SignupPasswordViewController { + + func postSignup() { + guard let name = name, + let password = passwordTextField.text + else { return } + AuthService.shared.postSignup(user: AuthRequest(name: name, + email: name, + password: password)) { result in + switch result { + case .success: + self.makeOKAlert(title: "회원가입 성공", + message: "회원가입 성공했습니다.", + okAction: { _ in self.goToAuthCompleteViewController() }, + completion: nil) + case .requestErr: + self.makeOKAlert(title: "회원가입 실패", message: "", okAction: nil, completion: nil) + case .pathErr: + print("pathErr") + case .serverErr: + print("serverErr") + case .networkFail: + print("networkFail") + } + } } } From 4509846870726d822ed5fa8b3859a38c67e729cf Mon Sep 17 00:00:00 2001 From: hyesuuou <68391767+hyesuuou@users.noreply.github.com> Date: Sun, 15 May 2022 19:17:39 +0900 Subject: [PATCH 4/4] =?UTF-8?q?chore:=20#8=20=EC=8B=9C=EC=9E=91=20?= =?UTF-8?q?=EC=8A=A4=ED=86=A0=EB=A6=AC=EB=B3=B4=EB=93=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Instagram-Clone/Instagram-Clone/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Instagram-Clone/Instagram-Clone/Info.plist b/Instagram-Clone/Instagram-Clone/Info.plist index dd3c9af..28686d2 100644 --- a/Instagram-Clone/Instagram-Clone/Info.plist +++ b/Instagram-Clone/Instagram-Clone/Info.plist @@ -16,7 +16,7 @@ UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate UISceneStoryboardFile - Main + Signin