From ea684b21e465b9156d8638a8adb88b1a009c63e6 Mon Sep 17 00:00:00 2001 From: Pradip Sutariya Date: Thu, 24 Oct 2019 16:19:54 +0530 Subject: [PATCH] "[Update] Make it compatible with Xcode 11 and update outdated pods" --- BSRadioWaves.xcodeproj/project.pbxproj | 24 +- .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + BSRadioWaves/Classes/BSAppDelegate.swift | 2 +- BSRadioWaves/Classes/Likes/BSLikesView.swift | 6 +- Pods/Alamofire/LICENSE | 19 + Pods/Alamofire/README.md | 242 ++ Pods/Alamofire/Source/AFError.swift | 460 +++ Pods/Alamofire/Source/Alamofire.swift | 465 +++ .../Source/DispatchQueue+Alamofire.swift | 37 + Pods/Alamofire/Source/MultipartFormData.swift | 580 +++ .../Source/NetworkReachabilityManager.swift | 238 ++ Pods/Alamofire/Source/Notifications.swift | 55 + Pods/Alamofire/Source/ParameterEncoding.swift | 483 +++ Pods/Alamofire/Source/Request.swift | 660 ++++ Pods/Alamofire/Source/Response.swift | 567 +++ .../Source/ResponseSerialization.swift | 715 ++++ Pods/Alamofire/Source/Result.swift | 300 ++ Pods/Alamofire/Source/ServerTrustPolicy.swift | 307 ++ Pods/Alamofire/Source/SessionDelegate.swift | 725 ++++ Pods/Alamofire/Source/SessionManager.swift | 899 +++++ Pods/Alamofire/Source/TaskDelegate.swift | 466 +++ Pods/Alamofire/Source/Timeline.swift | 136 + Pods/Alamofire/Source/Validation.swift | 321 ++ .../AlamofireObjectMapper.swift | 205 + Pods/AlamofireObjectMapper/LICENSE | 22 + Pods/AlamofireObjectMapper/README.md | 193 + Pods/CryptoSwift/LICENSE | 11 + Pods/CryptoSwift/README.md | 510 +++ .../Sources/CryptoSwift/AEAD/AEAD.swift | 40 + .../AEAD/AEADChaCha20Poly1305.swift | 59 + .../Sources/CryptoSwift/AES.Cryptors.swift | 35 + .../CryptoSwift/Sources/CryptoSwift/AES.swift | 539 +++ .../Sources/CryptoSwift/Array+Extension.swift | 148 + .../Sources/CryptoSwift/Authenticator.swift | 20 + .../CryptoSwift/BatchedCollection.swift | 63 + .../CryptoSwift/Sources/CryptoSwift/Bit.swift | 25 + .../Sources/CryptoSwift/BlockCipher.swift | 18 + .../Sources/CryptoSwift/BlockDecryptor.swift | 85 + .../Sources/CryptoSwift/BlockEncryptor.swift | 58 + .../CryptoSwift/BlockMode/BlockMode.swift | 24 + .../BlockMode/BlockModeOptions.swift | 27 + .../Sources/CryptoSwift/BlockMode/CBC.swift | 70 + .../Sources/CryptoSwift/BlockMode/CCM.swift | 357 ++ .../Sources/CryptoSwift/BlockMode/CFB.swift | 70 + .../Sources/CryptoSwift/BlockMode/CTR.swift | 134 + .../BlockMode/CipherModeWorker.swift | 61 + .../Sources/CryptoSwift/BlockMode/ECB.swift | 51 + .../Sources/CryptoSwift/BlockMode/GCM.swift | 370 ++ .../Sources/CryptoSwift/BlockMode/OFB.swift | 70 + .../Sources/CryptoSwift/BlockMode/PCBC.swift | 70 + .../Sources/CryptoSwift/Blowfish.swift | 537 +++ .../Sources/CryptoSwift/CBCMAC.swift | 30 + .../Sources/CryptoSwift/CMAC.swift | 104 + .../Sources/CryptoSwift/ChaCha20.swift | 347 ++ .../Sources/CryptoSwift/Checksum.swift | 193 + .../Sources/CryptoSwift/Cipher.swift | 47 + .../CryptoSwift/Collection+Extension.swift | 45 + .../Sources/CryptoSwift/CompactMap.swift | 23 + .../Sources/CryptoSwift/Cryptor.swift | 22 + .../Sources/CryptoSwift/Cryptors.swift | 42 + .../Sources/CryptoSwift/Digest.swift | 78 + .../Sources/CryptoSwift/DigestType.swift | 18 + .../Foundation/AES+Foundation.swift | 23 + .../Foundation/Array+Foundation.swift | 32 + .../Foundation/Blowfish+Foundation.swift | 23 + .../Foundation/ChaCha20+Foundation.swift | 22 + .../Foundation/Data+Extension.swift | 95 + .../Foundation/HMAC+Foundation.swift | 22 + .../Foundation/Rabbit+Foundation.swift | 26 + .../String+FoundationExtension.swift | 41 + .../Foundation/Utils+Foundation.swift | 27 + .../Sources/CryptoSwift/Generics.swift | 42 + .../Sources/CryptoSwift/HKDF.swift | 84 + .../Sources/CryptoSwift/HMAC.swift | 102 + .../Sources/CryptoSwift/Int+Extension.swift | 31 + .../CryptoSwift/Sources/CryptoSwift/MD5.swift | 161 + .../Sources/CryptoSwift/NoPadding.swift | 27 + .../Sources/CryptoSwift/Operators.swift | 32 + .../Sources/CryptoSwift/PKCS/PBKDF1.swift | 87 + .../Sources/CryptoSwift/PKCS/PBKDF2.swift | 116 + .../Sources/CryptoSwift/PKCS/PKCS5.swift | 22 + .../Sources/CryptoSwift/PKCS/PKCS7.swift | 18 + .../CryptoSwift/PKCS/PKCS7Padding.swift | 64 + .../Sources/CryptoSwift/Padding.swift | 49 + .../Sources/CryptoSwift/Poly1305.swift | 165 + .../Sources/CryptoSwift/Rabbit.swift | 217 + .../Sources/CryptoSwift/SHA1.swift | 145 + .../Sources/CryptoSwift/SHA2.swift | 345 ++ .../Sources/CryptoSwift/SHA3.swift | 289 ++ .../Sources/CryptoSwift/Scrypt.swift | 256 ++ .../Sources/CryptoSwift/SecureBytes.swift | 77 + .../Sources/CryptoSwift/StreamDecryptor.swift | 79 + .../Sources/CryptoSwift/StreamEncryptor.swift | 57 + .../CryptoSwift/String+Extension.swift | 81 + .../Sources/CryptoSwift/UInt128.swift | 90 + .../CryptoSwift/UInt16+Extension.swift | 37 + .../CryptoSwift/UInt32+Extension.swift | 48 + .../CryptoSwift/UInt64+Extension.swift | 43 + .../Sources/CryptoSwift/UInt8+Extension.swift | 72 + .../Sources/CryptoSwift/Updatable.swift | 97 + .../Sources/CryptoSwift/Utils.swift | 115 + .../Sources/CryptoSwift/ZeroPadding.swift | 38 + Pods/Manifest.lock | 39 + Pods/ObjectMapper/LICENSE | 8 + Pods/ObjectMapper/README-CN.md | 500 +++ .../Sources/CodableTransform.swift | 73 + .../Sources/CustomDateFormatTransform.swift | 40 + Pods/ObjectMapper/Sources/DataTransform.swift | 50 + .../Sources/DateFormatterTransform.swift | 54 + Pods/ObjectMapper/Sources/DateTransform.swift | 75 + .../Sources/DictionaryTransform.swift | 76 + Pods/ObjectMapper/Sources/EnumOperators.swift | 120 + Pods/ObjectMapper/Sources/EnumTransform.swift | 50 + Pods/ObjectMapper/Sources/FromJSON.swift | 202 + .../Sources/HexColorTransform.swift | 144 + .../Sources/ISO8601DateTransform.swift | 47 + .../Sources/ImmutableMappable.swift | 376 ++ .../Sources/IntegerOperators.swift | 171 + Pods/ObjectMapper/Sources/Map.swift | 204 + Pods/ObjectMapper/Sources/MapError.swift | 68 + Pods/ObjectMapper/Sources/Mappable.swift | 136 + Pods/ObjectMapper/Sources/Mapper.swift | 491 +++ .../Sources/NSDecimalNumberTransform.swift | 52 + Pods/ObjectMapper/Sources/Operators.swift | 398 ++ Pods/ObjectMapper/Sources/ToJSON.swift | 177 + Pods/ObjectMapper/Sources/TransformOf.swift | 48 + .../Sources/TransformOperators.swift | 709 ++++ Pods/ObjectMapper/Sources/TransformType.swift | 35 + Pods/ObjectMapper/Sources/URLTransform.swift | 67 + Pods/Pods.xcodeproj/project.pbxproj | 3485 +++++++++++++++++ Pods/SDWebImage/LICENSE | 20 + Pods/SDWebImage/README.md | 203 + .../SDWebImage/SDWebImage/NSButton+WebCache.h | 259 ++ .../SDWebImage/SDWebImage/NSButton+WebCache.m | 147 + .../SDWebImage/NSData+ImageContentType.h | 51 + .../SDWebImage/NSData+ImageContentType.m | 130 + Pods/SDWebImage/SDWebImage/NSImage+WebCache.h | 23 + Pods/SDWebImage/SDWebImage/NSImage+WebCache.m | 41 + .../SDWebImage/SDAnimatedImageRep.h | 20 + .../SDWebImage/SDAnimatedImageRep.m | 81 + Pods/SDWebImage/SDWebImage/SDImageCache.h | 310 ++ Pods/SDWebImage/SDWebImage/SDImageCache.m | 813 ++++ .../SDWebImage/SDImageCacheConfig.h | 79 + .../SDWebImage/SDImageCacheConfig.m | 30 + Pods/SDWebImage/SDWebImage/SDWebImageCoder.h | 119 + Pods/SDWebImage/SDWebImage/SDWebImageCoder.m | 31 + .../SDWebImage/SDWebImageCoderHelper.h | 52 + .../SDWebImage/SDWebImageCoderHelper.m | 258 ++ .../SDWebImage/SDWebImageCodersManager.h | 58 + .../SDWebImage/SDWebImageCodersManager.m | 148 + Pods/SDWebImage/SDWebImage/SDWebImageCompat.h | 107 + Pods/SDWebImage/SDWebImage/SDWebImageCompat.m | 71 + .../SDWebImage/SDWebImageDownloader.h | 292 ++ .../SDWebImage/SDWebImageDownloader.m | 439 +++ .../SDWebImageDownloaderOperation.h | 128 + .../SDWebImageDownloaderOperation.m | 506 +++ Pods/SDWebImage/SDWebImage/SDWebImageFrame.h | 34 + Pods/SDWebImage/SDWebImage/SDWebImageFrame.m | 28 + .../SDWebImage/SDWebImageGIFCoder.h | 23 + .../SDWebImage/SDWebImageGIFCoder.m | 184 + .../SDWebImage/SDWebImageImageIOCoder.h | 30 + .../SDWebImage/SDWebImageImageIOCoder.m | 536 +++ .../SDWebImage/SDWebImage/SDWebImageManager.h | 328 ++ .../SDWebImage/SDWebImage/SDWebImageManager.m | 370 ++ .../SDWebImage/SDWebImageOperation.h | 15 + .../SDWebImage/SDWebImagePrefetcher.h | 112 + .../SDWebImage/SDWebImagePrefetcher.m | 144 + .../SDWebImage/SDWebImageTransition.h | 98 + .../SDWebImage/SDWebImageTransition.m | 137 + .../SDWebImage/SDWebImage/UIButton+WebCache.h | 255 ++ .../SDWebImage/SDWebImage/UIButton+WebCache.m | 181 + .../SDWebImage/UIImage+ForceDecode.h | 17 + .../SDWebImage/UIImage+ForceDecode.m | 30 + Pods/SDWebImage/SDWebImage/UIImage+GIF.h | 25 + Pods/SDWebImage/SDWebImage/UIImage+GIF.m | 27 + .../SDWebImage/UIImage+MemoryCacheCost.h | 23 + .../SDWebImage/UIImage+MemoryCacheCost.m | 38 + .../SDWebImage/UIImage+MultiFormat.h | 37 + .../SDWebImage/UIImage+MultiFormat.m | 95 + .../UIImageView+HighlightedWebCache.h | 94 + .../UIImageView+HighlightedWebCache.m | 52 + .../SDWebImage/UIImageView+WebCache.h | 193 + .../SDWebImage/UIImageView+WebCache.m | 139 + Pods/SDWebImage/SDWebImage/UIView+WebCache.h | 140 + Pods/SDWebImage/SDWebImage/UIView+WebCache.m | 385 ++ .../SDWebImage/UIView+WebCacheOperation.h | 38 + .../SDWebImage/UIView+WebCacheOperation.m | 73 + .../Alamofire-iOS/Alamofire-iOS-Info.plist | 26 + .../Alamofire-iOS/Alamofire-iOS-dummy.m | 5 + .../Alamofire-iOS/Alamofire-iOS-prefix.pch | 12 + .../Alamofire-iOS/Alamofire-iOS-umbrella.h | 16 + .../Alamofire-iOS/Alamofire-iOS.modulemap | 6 + .../Alamofire-iOS/Alamofire-iOS.xcconfig | 10 + .../Alamofire-watchOS-Info.plist | 26 + .../Alamofire-watchOS-dummy.m | 5 + .../Alamofire-watchOS-prefix.pch | 12 + .../Alamofire-watchOS-umbrella.h | 16 + .../Alamofire-watchOS.modulemap | 6 + .../Alamofire-watchOS.xcconfig | 11 + .../AlamofireObjectMapper-iOS-Info.plist | 26 + .../AlamofireObjectMapper-iOS-dummy.m | 5 + .../AlamofireObjectMapper-iOS-prefix.pch | 12 + .../AlamofireObjectMapper-iOS-umbrella.h | 16 + .../AlamofireObjectMapper-iOS.modulemap | 6 + .../AlamofireObjectMapper-iOS.xcconfig | 11 + .../AlamofireObjectMapper-watchOS-Info.plist | 26 + .../AlamofireObjectMapper-watchOS-dummy.m | 5 + .../AlamofireObjectMapper-watchOS-prefix.pch | 12 + .../AlamofireObjectMapper-watchOS-umbrella.h | 16 + .../AlamofireObjectMapper-watchOS.modulemap | 6 + .../AlamofireObjectMapper-watchOS.xcconfig | 12 + .../CryptoSwift-iOS-Info.plist | 26 + .../CryptoSwift-iOS/CryptoSwift-iOS-dummy.m | 5 + .../CryptoSwift-iOS-prefix.pch | 12 + .../CryptoSwift-iOS-umbrella.h | 16 + .../CryptoSwift-iOS/CryptoSwift-iOS.modulemap | 6 + .../CryptoSwift-iOS/CryptoSwift-iOS.xcconfig | 10 + .../CryptoSwift-watchOS-Info.plist | 26 + .../CryptoSwift-watchOS-dummy.m | 5 + .../CryptoSwift-watchOS-prefix.pch | 12 + .../CryptoSwift-watchOS-umbrella.h | 16 + .../CryptoSwift-watchOS.modulemap | 6 + .../CryptoSwift-watchOS.xcconfig | 11 + .../ObjectMapper-iOS-Info.plist | 26 + .../ObjectMapper-iOS/ObjectMapper-iOS-dummy.m | 5 + .../ObjectMapper-iOS-prefix.pch | 12 + .../ObjectMapper-iOS-umbrella.h | 16 + .../ObjectMapper-iOS.modulemap | 6 + .../ObjectMapper-iOS.xcconfig | 10 + .../ObjectMapper-watchOS-Info.plist | 26 + .../ObjectMapper-watchOS-dummy.m | 5 + .../ObjectMapper-watchOS-prefix.pch | 12 + .../ObjectMapper-watchOS-umbrella.h | 16 + .../ObjectMapper-watchOS.modulemap | 6 + .../ObjectMapper-watchOS.xcconfig | 11 + .../Pods-BSRadioWaves-Info.plist | 26 + ...ods-BSRadioWaves-acknowledgements.markdown | 127 + .../Pods-BSRadioWaves-acknowledgements.plist | 189 + .../Pods-BSRadioWaves-dummy.m | 5 + .../Pods-BSRadioWaves-frameworks.sh | 181 + .../Pods-BSRadioWaves-umbrella.h | 16 + .../Pods-BSRadioWaves.debug.xcconfig | 12 + .../Pods-BSRadioWaves.modulemap | 6 + .../Pods-BSRadioWaves.release.xcconfig | 12 + .../Pods-Watch Extension-Info.plist | 26 + ...-Watch Extension-acknowledgements.markdown | 103 + ...ods-Watch Extension-acknowledgements.plist | 159 + .../Pods-Watch Extension-dummy.m | 5 + .../Pods-Watch Extension-frameworks.sh | 179 + .../Pods-Watch Extension-umbrella.h | 16 + .../Pods-Watch Extension.debug.xcconfig | 12 + .../Pods-Watch Extension.modulemap | 6 + .../Pods-Watch Extension.release.xcconfig | 12 + .../SDWebImage-iOS/SDWebImage-iOS-Info.plist | 26 + .../SDWebImage-iOS/SDWebImage-iOS-dummy.m | 5 + .../SDWebImage-iOS/SDWebImage-iOS-prefix.pch | 12 + .../SDWebImage-iOS/SDWebImage-iOS-umbrella.h | 44 + .../SDWebImage-iOS/SDWebImage-iOS.modulemap | 6 + .../SDWebImage-iOS/SDWebImage-iOS.xcconfig | 10 + .../SDWebImage-watchOS-Info.plist | 26 + .../SDWebImage-watchOS-dummy.m | 5 + .../SDWebImage-watchOS-prefix.pch | 12 + .../SDWebImage-watchOS-umbrella.h | 44 + .../SDWebImage-watchOS.modulemap | 6 + .../SDWebImage-watchOS.xcconfig | 11 + .../Toast-Swift/Toast-Swift-Info.plist | 26 + .../Toast-Swift/Toast-Swift-dummy.m | 5 + .../Toast-Swift/Toast-Swift-prefix.pch | 12 + .../Toast-Swift/Toast-Swift-umbrella.h | 16 + .../Toast-Swift/Toast-Swift.modulemap | 6 + .../Toast-Swift/Toast-Swift.xcconfig | 11 + Pods/Toast-Swift/LICENSE | 20 + Pods/Toast-Swift/README.md | 135 + Pods/Toast-Swift/Toast/Toast.swift | 782 ++++ 275 files changed, 35041 insertions(+), 12 deletions(-) create mode 100644 BSRadioWaves.xcworkspace/contents.xcworkspacedata create mode 100644 BSRadioWaves.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Pods/Alamofire/LICENSE create mode 100644 Pods/Alamofire/README.md create mode 100644 Pods/Alamofire/Source/AFError.swift create mode 100644 Pods/Alamofire/Source/Alamofire.swift create mode 100644 Pods/Alamofire/Source/DispatchQueue+Alamofire.swift create mode 100644 Pods/Alamofire/Source/MultipartFormData.swift create mode 100644 Pods/Alamofire/Source/NetworkReachabilityManager.swift create mode 100644 Pods/Alamofire/Source/Notifications.swift create mode 100644 Pods/Alamofire/Source/ParameterEncoding.swift create mode 100644 Pods/Alamofire/Source/Request.swift create mode 100644 Pods/Alamofire/Source/Response.swift create mode 100644 Pods/Alamofire/Source/ResponseSerialization.swift create mode 100644 Pods/Alamofire/Source/Result.swift create mode 100644 Pods/Alamofire/Source/ServerTrustPolicy.swift create mode 100644 Pods/Alamofire/Source/SessionDelegate.swift create mode 100644 Pods/Alamofire/Source/SessionManager.swift create mode 100644 Pods/Alamofire/Source/TaskDelegate.swift create mode 100644 Pods/Alamofire/Source/Timeline.swift create mode 100644 Pods/Alamofire/Source/Validation.swift create mode 100644 Pods/AlamofireObjectMapper/AlamofireObjectMapper/AlamofireObjectMapper.swift create mode 100644 Pods/AlamofireObjectMapper/LICENSE create mode 100644 Pods/AlamofireObjectMapper/README.md create mode 100644 Pods/CryptoSwift/LICENSE create mode 100644 Pods/CryptoSwift/README.md create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEAD.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEADChaCha20Poly1305.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/AES.Cryptors.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/AES.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Array+Extension.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Authenticator.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BatchedCollection.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Bit.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockCipher.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockDecryptor.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockEncryptor.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockMode.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockModeOptions.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CBC.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CCM.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CFB.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CTR.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CipherModeWorker.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/ECB.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/GCM.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/OFB.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/PCBC.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Blowfish.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/CBCMAC.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/CMAC.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/ChaCha20.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Checksum.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Cipher.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Collection+Extension.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/CompactMap.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Cryptor.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Cryptors.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Digest.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/DigestType.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Foundation/AES+Foundation.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Array+Foundation.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Blowfish+Foundation.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Foundation/ChaCha20+Foundation.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Data+Extension.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Foundation/HMAC+Foundation.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Rabbit+Foundation.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Foundation/String+FoundationExtension.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Utils+Foundation.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Generics.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/HKDF.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/HMAC.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Int+Extension.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/MD5.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/NoPadding.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Operators.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PBKDF1.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PBKDF2.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PKCS5.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PKCS7.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PKCS7Padding.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Padding.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Poly1305.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Rabbit.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/SHA1.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/SHA2.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/SHA3.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Scrypt.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/SecureBytes.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/StreamDecryptor.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/StreamEncryptor.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/String+Extension.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/UInt128.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/UInt16+Extension.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/UInt32+Extension.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/UInt64+Extension.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/UInt8+Extension.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Updatable.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/Utils.swift create mode 100644 Pods/CryptoSwift/Sources/CryptoSwift/ZeroPadding.swift create mode 100644 Pods/Manifest.lock create mode 100644 Pods/ObjectMapper/LICENSE create mode 100644 Pods/ObjectMapper/README-CN.md create mode 100644 Pods/ObjectMapper/Sources/CodableTransform.swift create mode 100644 Pods/ObjectMapper/Sources/CustomDateFormatTransform.swift create mode 100644 Pods/ObjectMapper/Sources/DataTransform.swift create mode 100644 Pods/ObjectMapper/Sources/DateFormatterTransform.swift create mode 100644 Pods/ObjectMapper/Sources/DateTransform.swift create mode 100644 Pods/ObjectMapper/Sources/DictionaryTransform.swift create mode 100644 Pods/ObjectMapper/Sources/EnumOperators.swift create mode 100644 Pods/ObjectMapper/Sources/EnumTransform.swift create mode 100755 Pods/ObjectMapper/Sources/FromJSON.swift create mode 100644 Pods/ObjectMapper/Sources/HexColorTransform.swift create mode 100644 Pods/ObjectMapper/Sources/ISO8601DateTransform.swift create mode 100644 Pods/ObjectMapper/Sources/ImmutableMappable.swift create mode 100644 Pods/ObjectMapper/Sources/IntegerOperators.swift create mode 100644 Pods/ObjectMapper/Sources/Map.swift create mode 100644 Pods/ObjectMapper/Sources/MapError.swift create mode 100644 Pods/ObjectMapper/Sources/Mappable.swift create mode 100755 Pods/ObjectMapper/Sources/Mapper.swift create mode 100644 Pods/ObjectMapper/Sources/NSDecimalNumberTransform.swift create mode 100755 Pods/ObjectMapper/Sources/Operators.swift create mode 100644 Pods/ObjectMapper/Sources/ToJSON.swift create mode 100644 Pods/ObjectMapper/Sources/TransformOf.swift create mode 100644 Pods/ObjectMapper/Sources/TransformOperators.swift create mode 100644 Pods/ObjectMapper/Sources/TransformType.swift create mode 100644 Pods/ObjectMapper/Sources/URLTransform.swift create mode 100644 Pods/Pods.xcodeproj/project.pbxproj create mode 100644 Pods/SDWebImage/LICENSE create mode 100644 Pods/SDWebImage/README.md create mode 100644 Pods/SDWebImage/SDWebImage/NSButton+WebCache.h create mode 100644 Pods/SDWebImage/SDWebImage/NSButton+WebCache.m create mode 100644 Pods/SDWebImage/SDWebImage/NSData+ImageContentType.h create mode 100644 Pods/SDWebImage/SDWebImage/NSData+ImageContentType.m create mode 100644 Pods/SDWebImage/SDWebImage/NSImage+WebCache.h create mode 100644 Pods/SDWebImage/SDWebImage/NSImage+WebCache.m create mode 100644 Pods/SDWebImage/SDWebImage/SDAnimatedImageRep.h create mode 100644 Pods/SDWebImage/SDWebImage/SDAnimatedImageRep.m create mode 100644 Pods/SDWebImage/SDWebImage/SDImageCache.h create mode 100644 Pods/SDWebImage/SDWebImage/SDImageCache.m create mode 100644 Pods/SDWebImage/SDWebImage/SDImageCacheConfig.h create mode 100644 Pods/SDWebImage/SDWebImage/SDImageCacheConfig.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageCoder.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageCoder.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageCoderHelper.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageCoderHelper.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageCodersManager.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageCodersManager.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageCompat.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageCompat.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageDownloader.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageDownloader.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageFrame.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageFrame.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageGIFCoder.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageGIFCoder.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageManager.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageManager.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageOperation.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.m create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageTransition.h create mode 100644 Pods/SDWebImage/SDWebImage/SDWebImageTransition.m create mode 100644 Pods/SDWebImage/SDWebImage/UIButton+WebCache.h create mode 100644 Pods/SDWebImage/SDWebImage/UIButton+WebCache.m create mode 100644 Pods/SDWebImage/SDWebImage/UIImage+ForceDecode.h create mode 100644 Pods/SDWebImage/SDWebImage/UIImage+ForceDecode.m create mode 100644 Pods/SDWebImage/SDWebImage/UIImage+GIF.h create mode 100644 Pods/SDWebImage/SDWebImage/UIImage+GIF.m create mode 100644 Pods/SDWebImage/SDWebImage/UIImage+MemoryCacheCost.h create mode 100644 Pods/SDWebImage/SDWebImage/UIImage+MemoryCacheCost.m create mode 100644 Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.h create mode 100644 Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.m create mode 100644 Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.h create mode 100644 Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.m create mode 100644 Pods/SDWebImage/SDWebImage/UIImageView+WebCache.h create mode 100644 Pods/SDWebImage/SDWebImage/UIImageView+WebCache.m create mode 100644 Pods/SDWebImage/SDWebImage/UIView+WebCache.h create mode 100644 Pods/SDWebImage/SDWebImage/UIView+WebCache.m create mode 100644 Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.h create mode 100644 Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.m create mode 100644 Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-Info.plist create mode 100644 Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-dummy.m create mode 100644 Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-prefix.pch create mode 100644 Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-umbrella.h create mode 100644 Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS.modulemap create mode 100644 Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS.xcconfig create mode 100644 Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-Info.plist create mode 100644 Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-dummy.m create mode 100644 Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-prefix.pch create mode 100644 Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-umbrella.h create mode 100644 Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS.modulemap create mode 100644 Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS.xcconfig create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-Info.plist create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-dummy.m create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-prefix.pch create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-umbrella.h create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS.modulemap create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS.xcconfig create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-Info.plist create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-dummy.m create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-prefix.pch create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-umbrella.h create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.modulemap create mode 100644 Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.xcconfig create mode 100644 Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-Info.plist create mode 100644 Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-dummy.m create mode 100644 Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-prefix.pch create mode 100644 Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-umbrella.h create mode 100644 Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS.modulemap create mode 100644 Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS.xcconfig create mode 100644 Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-Info.plist create mode 100644 Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-dummy.m create mode 100644 Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-prefix.pch create mode 100644 Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-umbrella.h create mode 100644 Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS.modulemap create mode 100644 Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS.xcconfig create mode 100644 Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-Info.plist create mode 100644 Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-dummy.m create mode 100644 Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-prefix.pch create mode 100644 Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-umbrella.h create mode 100644 Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS.modulemap create mode 100644 Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS.xcconfig create mode 100644 Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-Info.plist create mode 100644 Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-dummy.m create mode 100644 Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-prefix.pch create mode 100644 Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-umbrella.h create mode 100644 Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS.modulemap create mode 100644 Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS.xcconfig create mode 100644 Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-Info.plist create mode 100644 Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-acknowledgements.markdown create mode 100644 Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-acknowledgements.plist create mode 100644 Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-dummy.m create mode 100755 Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh create mode 100644 Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-umbrella.h create mode 100644 Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.debug.xcconfig create mode 100644 Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.modulemap create mode 100644 Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.release.xcconfig create mode 100644 Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-Info.plist create mode 100644 Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-acknowledgements.markdown create mode 100644 Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-acknowledgements.plist create mode 100644 Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-dummy.m create mode 100755 Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh create mode 100644 Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-umbrella.h create mode 100644 Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.debug.xcconfig create mode 100644 Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.modulemap create mode 100644 Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.release.xcconfig create mode 100644 Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-Info.plist create mode 100644 Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-dummy.m create mode 100644 Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-prefix.pch create mode 100644 Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-umbrella.h create mode 100644 Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS.modulemap create mode 100644 Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS.xcconfig create mode 100644 Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-Info.plist create mode 100644 Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-dummy.m create mode 100644 Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-prefix.pch create mode 100644 Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-umbrella.h create mode 100644 Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS.modulemap create mode 100644 Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS.xcconfig create mode 100644 Pods/Target Support Files/Toast-Swift/Toast-Swift-Info.plist create mode 100644 Pods/Target Support Files/Toast-Swift/Toast-Swift-dummy.m create mode 100644 Pods/Target Support Files/Toast-Swift/Toast-Swift-prefix.pch create mode 100644 Pods/Target Support Files/Toast-Swift/Toast-Swift-umbrella.h create mode 100644 Pods/Target Support Files/Toast-Swift/Toast-Swift.modulemap create mode 100644 Pods/Target Support Files/Toast-Swift/Toast-Swift.xcconfig create mode 100644 Pods/Toast-Swift/LICENSE create mode 100644 Pods/Toast-Swift/README.md create mode 100644 Pods/Toast-Swift/Toast/Toast.swift diff --git a/BSRadioWaves.xcodeproj/project.pbxproj b/BSRadioWaves.xcodeproj/project.pbxproj index 1479b83..66c579a 100644 --- a/BSRadioWaves.xcodeproj/project.pbxproj +++ b/BSRadioWaves.xcodeproj/project.pbxproj @@ -50,7 +50,6 @@ 062E7F0F1FB1A73500217A3B /* BSPlayButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062E7F0E1FB1A73500217A3B /* BSPlayButton.swift */; }; 062E7F111FB1A96900217A3B /* BSPlayPauseIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062E7F101FB1A96900217A3B /* BSPlayPauseIconView.swift */; }; 062E7F131FB1BF4A00217A3B /* BSTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 062E7F121FB1BF4A00217A3B /* BSTabBarController.swift */; }; - 063A3B091FBB0DBD00E64373 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 063A3B081FBB0DBD00E64373 /* Assets.xcassets */; }; 063A3B0A1FBB0DCF00E64373 /* Assets.xcassets in Sources */ = {isa = PBXBuildFile; fileRef = 063A3B081FBB0DBD00E64373 /* Assets.xcassets */; }; 0640D24D1FC2E8D300E9ECB2 /* BSCategoriesController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06B22B2E1FC2CA070085FF30 /* BSCategoriesController.swift */; }; 06593EEC1FAA51BA00689EA7 /* BSCategoriesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06593EE41FAA51BA00689EA7 /* BSCategoriesViewController.swift */; }; @@ -97,7 +96,6 @@ 06B22B171FC1A24B0085FF30 /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06B22B161FC1A24B0085FF30 /* ExtensionDelegate.swift */; }; 06B22B191FC1A24B0085FF30 /* NotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06B22B181FC1A24B0085FF30 /* NotificationController.swift */; }; 06B22B1B1FC1A24B0085FF30 /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06B22B1A1FC1A24B0085FF30 /* ComplicationController.swift */; }; - 06B22B1D1FC1A24B0085FF30 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 06B22B1C1FC1A24B0085FF30 /* Assets.xcassets */; }; 06B22B221FC1A24B0085FF30 /* Watch.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 06B22B031FC1A24A0085FF30 /* Watch.app */; }; 06CC90A41FC56A8B0033EF22 /* BSWavesDrawerProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CC90A31FC56A8B0033EF22 /* BSWavesDrawerProxy.swift */; }; 06CC90A71FC56E9F0033EF22 /* BSWavesDrawer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06CC90A61FC56E9E0033EF22 /* BSWavesDrawer.swift */; }; @@ -672,7 +670,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0910; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1100; ORGANIZATIONNAME = iBlacksus; TargetAttributes = { 06593EC51FA91A5D00689EA7 = { @@ -721,7 +719,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 063A3B091FBB0DBD00E64373 /* Assets.xcassets in Resources */, 06EF3E371FBC27BD00CB18E4 /* BSLikeCell.xib in Resources */, 061C0AD31FBAD1CF003E6066 /* Roboto-ThinItalic.ttf in Resources */, 061C0AD41FBAD1CF003E6066 /* Roboto-BoldItalic.ttf in Resources */, @@ -768,7 +765,6 @@ buildActionMask = 2147483647; files = ( 061F72F71FC6A5E2003919D5 /* Assets.xcassets in Resources */, - 06B22B1D1FC1A24B0085FF30 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -817,7 +813,7 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh", + "${PODS_ROOT}/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Alamofire-iOS/Alamofire.framework", "${BUILT_PRODUCTS_DIR}/AlamofireObjectMapper-iOS/AlamofireObjectMapper.framework", "${BUILT_PRODUCTS_DIR}/CryptoSwift-iOS/CryptoSwift.framework", @@ -836,7 +832,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; B018866A18BC29AF68E7962F /* [CP] Embed Pods Frameworks */ = { @@ -845,7 +841,7 @@ files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh", + "${PODS_ROOT}/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh", "${BUILT_PRODUCTS_DIR}/Alamofire-watchOS/Alamofire.framework", "${BUILT_PRODUCTS_DIR}/AlamofireObjectMapper-watchOS/AlamofireObjectMapper.framework", "${BUILT_PRODUCTS_DIR}/CryptoSwift-watchOS/CryptoSwift.framework", @@ -862,7 +858,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -1010,6 +1006,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -1017,6 +1014,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -1067,6 +1065,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -1074,6 +1073,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -1114,6 +1114,7 @@ INFOPLIST_FILE = BSRadioWaves/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = "5f9082d6-2a97-4799-96ee-dceaf03439a6"; @@ -1135,6 +1136,7 @@ INFOPLIST_FILE = BSRadioWaves/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1152,6 +1154,7 @@ DEVELOPMENT_TEAM = LS7LKYHTNJ; INFOPLIST_FILE = "Watch Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves.watchkitapp.watchkitextension; PRODUCT_NAME = "${TARGET_NAME}"; PROVISIONING_PROFILE = "f6d5cd5e-aa4c-4380-a6c2-14f9fad81fd8"; @@ -1173,6 +1176,7 @@ DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = "Watch Extension/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; + ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves.watchkitapp.watchkitextension; PRODUCT_NAME = "${TARGET_NAME}"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1195,6 +1199,7 @@ IBSC_MODULE = Watch_Extension; INFOPLIST_FILE = Watch/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = "f6d5cd5e-aa4c-4380-a6c2-14f9fad81fd8"; @@ -1219,6 +1224,7 @@ IBSC_MODULE = Watch_Extension; INFOPLIST_FILE = Watch/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = iBlacksus.BSRadioWaves.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/BSRadioWaves.xcworkspace/contents.xcworkspacedata b/BSRadioWaves.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..58a7f26 --- /dev/null +++ b/BSRadioWaves.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/BSRadioWaves.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/BSRadioWaves.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/BSRadioWaves.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/BSRadioWaves/Classes/BSAppDelegate.swift b/BSRadioWaves/Classes/BSAppDelegate.swift index 55d314a..f29a1e0 100644 --- a/BSRadioWaves/Classes/BSAppDelegate.swift +++ b/BSRadioWaves/Classes/BSAppDelegate.swift @@ -22,7 +22,7 @@ class BSAppDelegate: UIResponder, UIApplicationDelegate { var style = ToastStyle() style.backgroundColor = UIColor.black.withAlphaComponent(0.4) ToastManager.shared.style = style - ToastManager.shared.tapToDismissEnabled = true + ToastManager.shared.isTapToDismissEnabled = true SDImageCache.shared().config.maxCacheAge = 60 * 60 * 24 diff --git a/BSRadioWaves/Classes/Likes/BSLikesView.swift b/BSRadioWaves/Classes/Likes/BSLikesView.swift index da69bb5..b4395ae 100644 --- a/BSRadioWaves/Classes/Likes/BSLikesView.swift +++ b/BSRadioWaves/Classes/Likes/BSLikesView.swift @@ -40,9 +40,11 @@ class BSLikesView: UICollectionView, UICollectionViewDelegate, UICollectionViewD let cellRect: CGRect = (attributes?.frame)! let view: UIView = collectionView.superview! let cellFrameInSuperview = collectionView.convert(cellRect, to: view) - let position = CGPoint(x: cellFrameInSuperview.midX, y: cellFrameInSuperview.midY) +// let position = CGPoint(x: cellFrameInSuperview.midX, y: cellFrameInSuperview.midY) - self.makeToast("Copied to clipboard", duration: 1.25, position: position) + self.makeToast("Copied to clipboard", duration: 1.25, position: .bottom, title: "", image: nil) { (success) in + + } } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { diff --git a/Pods/Alamofire/LICENSE b/Pods/Alamofire/LICENSE new file mode 100644 index 0000000..38a301a --- /dev/null +++ b/Pods/Alamofire/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Pods/Alamofire/README.md b/Pods/Alamofire/README.md new file mode 100644 index 0000000..9fdc9c7 --- /dev/null +++ b/Pods/Alamofire/README.md @@ -0,0 +1,242 @@ +![Alamofire: Elegant Networking in Swift](https://raw.githubusercontent.com/Alamofire/Alamofire/master/alamofire.png) + +[![Build Status](https://travis-ci.org/Alamofire/Alamofire.svg?branch=master)](https://travis-ci.org/Alamofire/Alamofire) +[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/Alamofire.svg)](https://img.shields.io/cocoapods/v/Alamofire.svg) +[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) +[![Platform](https://img.shields.io/cocoapods/p/Alamofire.svg?style=flat)](https://alamofire.github.io/Alamofire) +[![Twitter](https://img.shields.io/badge/twitter-@AlamofireSF-blue.svg?style=flat)](https://twitter.com/AlamofireSF) +[![Gitter](https://badges.gitter.im/Alamofire/Alamofire.svg)](https://gitter.im/Alamofire/Alamofire?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +Alamofire is an HTTP networking library written in Swift. + +- [Features](#features) +- [Component Libraries](#component-libraries) +- [Requirements](#requirements) +- [Migration Guides](#migration-guides) +- [Communication](#communication) +- [Installation](#installation) +- [Usage](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md) + - **Intro -** [Making a Request](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#making-a-request), [Response Handling](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-handling), [Response Validation](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-validation), [Response Caching](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#response-caching) + - **HTTP -** [HTTP Methods](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#http-methods), [Parameter Encoding](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#parameter-encoding), [HTTP Headers](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#http-headers), [Authentication](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#authentication) + - **Large Data -** [Downloading Data to a File](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#downloading-data-to-a-file), [Uploading Data to a Server](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#uploading-data-to-a-server) + - **Tools -** [Statistical Metrics](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#statistical-metrics), [cURL Command Output](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#curl-command-output) +- [Advanced Usage](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md) + - **URL Session -** [Session Manager](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#session-manager), [Session Delegate](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#session-delegate), [Request](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#request) + - **Routing -** [Routing Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#routing-requests), [Adapting and Retrying Requests](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#adapting-and-retrying-requests) + - **Model Objects -** [Custom Response Serialization](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#custom-response-serialization) + - **Connection -** [Security](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#security), [Network Reachability](https://github.com/Alamofire/Alamofire/blob/master/Documentation/AdvancedUsage.md#network-reachability) +- [Open Radars](#open-radars) +- [FAQ](#faq) +- [Credits](#credits) +- [Donations](#donations) +- [License](#license) + +## Features + +- [x] Chainable Request / Response Methods +- [x] URL / JSON / plist Parameter Encoding +- [x] Upload File / Data / Stream / MultipartFormData +- [x] Download File using Request or Resume Data +- [x] Authentication with URLCredential +- [x] HTTP Response Validation +- [x] Upload and Download Progress Closures with Progress +- [x] cURL Command Output +- [x] Dynamically Adapt and Retry Requests +- [x] TLS Certificate and Public Key Pinning +- [x] Network Reachability +- [x] Comprehensive Unit and Integration Test Coverage +- [x] [Complete Documentation](https://alamofire.github.io/Alamofire) + +## Component Libraries + +In order to keep Alamofire focused specifically on core networking implementations, additional component libraries have been created by the [Alamofire Software Foundation](https://github.com/Alamofire/Foundation) to bring additional functionality to the Alamofire ecosystem. + +- [AlamofireImage](https://github.com/Alamofire/AlamofireImage) - An image library including image response serializers, `UIImage` and `UIImageView` extensions, custom image filters, an auto-purging in-memory cache and a priority-based image downloading system. +- [AlamofireNetworkActivityIndicator](https://github.com/Alamofire/AlamofireNetworkActivityIndicator) - Controls the visibility of the network activity indicator on iOS using Alamofire. It contains configurable delay timers to help mitigate flicker and can support `URLSession` instances not managed by Alamofire. + +## Requirements + +- iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+ +- Xcode 8.3+ +- Swift 3.1+ + +## Migration Guides + +- [Alamofire 4.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%204.0%20Migration%20Guide.md) +- [Alamofire 3.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%203.0%20Migration%20Guide.md) +- [Alamofire 2.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%202.0%20Migration%20Guide.md) + +## Communication +- If you **need help with making network requests**, use [Stack Overflow](https://stackoverflow.com/questions/tagged/alamofire) and tag `alamofire`. +- If you need to **find or understand an API**, check [our documentation](http://alamofire.github.io/Alamofire/) or [Apple's documentation for `URLSession`](https://developer.apple.com/documentation/foundation/url_loading_system), on top of which Alamofire is built. +- If you need **help with an Alamofire feature**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire). +- If you'd like to **discuss Alamofire best practices**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire). +- If you'd like to **discuss a feature request**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire). +- If you **found a bug**, open an issue and follow the guide. The more detail the better! +- If you **want to contribute**, submit a pull request. + +## Installation + +### CocoaPods + +[CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: + +```bash +$ gem install cocoapods +``` + +> CocoaPods 1.7+ is required to build Alamofire 4.9+. + +To integrate Alamofire into your Xcode project using CocoaPods, specify it in your `Podfile`: + +```ruby +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '10.0' +use_frameworks! + +target '' do + pod 'Alamofire', '~> 4.9' +end +``` + +Then, run the following command: + +```bash +$ pod install +``` + +### Carthage + +[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. + +You can install Carthage with [Homebrew](https://brew.sh/) using the following command: + +```bash +$ brew install carthage +``` + +To integrate Alamofire into your Xcode project using Carthage, specify it in your `Cartfile`: + +```ogdl +github "Alamofire/Alamofire" ~> 4.9 +``` + +Run `carthage update` to build the framework and drag the built `Alamofire.framework` into your Xcode project. + +### Swift Package Manager + +The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. It is in early development, but Alamofire does support its use on supported platforms. + +Once you have your Swift package set up, adding Alamofire as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. + +#### Swift 3 + +```swift +dependencies: [ + .Package(url: "https://github.com/Alamofire/Alamofire.git", majorVersion: 4) +] +``` + +#### Swift 4 + +```swift +dependencies: [ + .package(url: "https://github.com/Alamofire/Alamofire.git", from: "4.9.0") +] +``` + +### Manually + +If you prefer not to use any of the aforementioned dependency managers, you can integrate Alamofire into your project manually. + +#### Embedded Framework + +- Open up Terminal, `cd` into your top-level project directory, and run the following command "if" your project is not initialized as a git repository: + + ```bash + $ git init + ``` + +- Add Alamofire as a git [submodule](https://git-scm.com/docs/git-submodule) by running the following command: + + ```bash + $ git submodule add https://github.com/Alamofire/Alamofire.git + ``` + +- Open the new `Alamofire` folder, and drag the `Alamofire.xcodeproj` into the Project Navigator of your application's Xcode project. + + > It should appear nested underneath your application's blue project icon. Whether it is above or below all the other Xcode groups does not matter. + +- Select the `Alamofire.xcodeproj` in the Project Navigator and verify the deployment target matches that of your application target. +- Next, select your application project in the Project Navigator (blue project icon) to navigate to the target configuration window and select the application target under the "Targets" heading in the sidebar. +- In the tab bar at the top of that window, open the "General" panel. +- Click on the `+` button under the "Embedded Binaries" section. +- You will see two different `Alamofire.xcodeproj` folders each with two different versions of the `Alamofire.framework` nested inside a `Products` folder. + + > It does not matter which `Products` folder you choose from, but it does matter whether you choose the top or bottom `Alamofire.framework`. + +- Select the top `Alamofire.framework` for iOS and the bottom one for OS X. + + > You can verify which one you selected by inspecting the build log for your project. The build target for `Alamofire` will be listed as either `Alamofire iOS`, `Alamofire macOS`, `Alamofire tvOS` or `Alamofire watchOS`. + +- And that's it! + + > The `Alamofire.framework` is automagically added as a target dependency, linked framework and embedded framework in a copy files build phase which is all you need to build on the simulator and a device. + +## Open Radars + +The following radars have some effect on the current implementation of Alamofire. + +- [`rdar://21349340`](http://www.openradar.me/radar?id=5517037090635776) - Compiler throwing warning due to toll-free bridging issue in test case +- `rdar://26870455` - Background URL Session Configurations do not work in the simulator +- `rdar://26849668` - Some URLProtocol APIs do not properly handle `URLRequest` +- [`rdar://36082113`](http://openradar.appspot.com/radar?id=4942308441063424) - `URLSessionTaskMetrics` failing to link on watchOS 3.0+ + +## Resolved Radars + +The following radars have been resolved over time after being filed against the Alamofire project. + +- [`rdar://26761490`](http://www.openradar.me/radar?id=5010235949318144) - Swift string interpolation causing memory leak with common usage (Resolved on 9/1/17 in Xcode 9 beta 6). + +## FAQ + +### What's the origin of the name Alamofire? + +Alamofire is named after the [Alamo Fire flower](https://aggie-horticulture.tamu.edu/wildseed/alamofire.html), a hybrid variant of the Bluebonnet, the official state flower of Texas. + +### What logic belongs in a Router vs. a Request Adapter? + +Simple, static data such as paths, parameters and common headers belong in the `Router`. Dynamic data such as an `Authorization` header whose value can changed based on an authentication system belongs in a `RequestAdapter`. + +The reason the dynamic data MUST be placed into the `RequestAdapter` is to support retry operations. When a `Request` is retried, the original request is not rebuilt meaning the `Router` will not be called again. The `RequestAdapter` is called again allowing the dynamic data to be updated on the original request before retrying the `Request`. + +## Credits + +Alamofire is owned and maintained by the [Alamofire Software Foundation](http://alamofire.org). You can follow them on Twitter at [@AlamofireSF](https://twitter.com/AlamofireSF) for project updates and releases. + +### Security Disclosure + +If you believe you have identified a security vulnerability with Alamofire, you should report it as soon as possible via email to security@alamofire.org. Please do not post it to a public issue tracker. + +## Donations + +The [ASF](https://github.com/Alamofire/Foundation#members) is looking to raise money to officially stay registered as a federal non-profit organization. +Registering will allow us members to gain some legal protections and also allow us to put donations to use, tax free. +Donating to the ASF will enable us to: + +- Pay our yearly legal fees to keep the non-profit in good status +- Pay for our mail servers to help us stay on top of all questions and security issues +- Potentially fund test servers to make it easier for us to test the edge cases +- Potentially fund developers to work on one of our projects full-time + +The community adoption of the ASF libraries has been amazing. +We are greatly humbled by your enthusiasm around the projects, and want to continue to do everything we can to move the needle forward. +With your continued support, the ASF will be able to improve its reach and also provide better legal safety for the core members. +If you use any of our libraries for work, see if your employers would be interested in donating. +Any amount you can donate today to help us reach our goal would be greatly appreciated. + +[![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) + +## License + +Alamofire is released under the MIT license. [See LICENSE](https://github.com/Alamofire/Alamofire/blob/master/LICENSE) for details. diff --git a/Pods/Alamofire/Source/AFError.swift b/Pods/Alamofire/Source/AFError.swift new file mode 100644 index 0000000..b163f60 --- /dev/null +++ b/Pods/Alamofire/Source/AFError.swift @@ -0,0 +1,460 @@ +// +// AFError.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// `AFError` is the error type returned by Alamofire. It encompasses a few different types of errors, each with +/// their own associated reasons. +/// +/// - invalidURL: Returned when a `URLConvertible` type fails to create a valid `URL`. +/// - parameterEncodingFailed: Returned when a parameter encoding object throws an error during the encoding process. +/// - multipartEncodingFailed: Returned when some step in the multipart encoding process fails. +/// - responseValidationFailed: Returned when a `validate()` call fails. +/// - responseSerializationFailed: Returned when a response serializer encounters an error in the serialization process. +public enum AFError: Error { + /// The underlying reason the parameter encoding error occurred. + /// + /// - missingURL: The URL request did not have a URL to encode. + /// - jsonEncodingFailed: JSON serialization failed with an underlying system error during the + /// encoding process. + /// - propertyListEncodingFailed: Property list serialization failed with an underlying system error during + /// encoding process. + public enum ParameterEncodingFailureReason { + case missingURL + case jsonEncodingFailed(error: Error) + case propertyListEncodingFailed(error: Error) + } + + /// The underlying reason the multipart encoding error occurred. + /// + /// - bodyPartURLInvalid: The `fileURL` provided for reading an encodable body part isn't a + /// file URL. + /// - bodyPartFilenameInvalid: The filename of the `fileURL` provided has either an empty + /// `lastPathComponent` or `pathExtension. + /// - bodyPartFileNotReachable: The file at the `fileURL` provided was not reachable. + /// - bodyPartFileNotReachableWithError: Attempting to check the reachability of the `fileURL` provided threw + /// an error. + /// - bodyPartFileIsDirectory: The file at the `fileURL` provided is actually a directory. + /// - bodyPartFileSizeNotAvailable: The size of the file at the `fileURL` provided was not returned by + /// the system. + /// - bodyPartFileSizeQueryFailedWithError: The attempt to find the size of the file at the `fileURL` provided + /// threw an error. + /// - bodyPartInputStreamCreationFailed: An `InputStream` could not be created for the provided `fileURL`. + /// - outputStreamCreationFailed: An `OutputStream` could not be created when attempting to write the + /// encoded data to disk. + /// - outputStreamFileAlreadyExists: The encoded body data could not be writtent disk because a file + /// already exists at the provided `fileURL`. + /// - outputStreamURLInvalid: The `fileURL` provided for writing the encoded body data to disk is + /// not a file URL. + /// - outputStreamWriteFailed: The attempt to write the encoded body data to disk failed with an + /// underlying error. + /// - inputStreamReadFailed: The attempt to read an encoded body part `InputStream` failed with + /// underlying system error. + public enum MultipartEncodingFailureReason { + case bodyPartURLInvalid(url: URL) + case bodyPartFilenameInvalid(in: URL) + case bodyPartFileNotReachable(at: URL) + case bodyPartFileNotReachableWithError(atURL: URL, error: Error) + case bodyPartFileIsDirectory(at: URL) + case bodyPartFileSizeNotAvailable(at: URL) + case bodyPartFileSizeQueryFailedWithError(forURL: URL, error: Error) + case bodyPartInputStreamCreationFailed(for: URL) + + case outputStreamCreationFailed(for: URL) + case outputStreamFileAlreadyExists(at: URL) + case outputStreamURLInvalid(url: URL) + case outputStreamWriteFailed(error: Error) + + case inputStreamReadFailed(error: Error) + } + + /// The underlying reason the response validation error occurred. + /// + /// - dataFileNil: The data file containing the server response did not exist. + /// - dataFileReadFailed: The data file containing the server response could not be read. + /// - missingContentType: The response did not contain a `Content-Type` and the `acceptableContentTypes` + /// provided did not contain wildcard type. + /// - unacceptableContentType: The response `Content-Type` did not match any type in the provided + /// `acceptableContentTypes`. + /// - unacceptableStatusCode: The response status code was not acceptable. + public enum ResponseValidationFailureReason { + case dataFileNil + case dataFileReadFailed(at: URL) + case missingContentType(acceptableContentTypes: [String]) + case unacceptableContentType(acceptableContentTypes: [String], responseContentType: String) + case unacceptableStatusCode(code: Int) + } + + /// The underlying reason the response serialization error occurred. + /// + /// - inputDataNil: The server response contained no data. + /// - inputDataNilOrZeroLength: The server response contained no data or the data was zero length. + /// - inputFileNil: The file containing the server response did not exist. + /// - inputFileReadFailed: The file containing the server response could not be read. + /// - stringSerializationFailed: String serialization failed using the provided `String.Encoding`. + /// - jsonSerializationFailed: JSON serialization failed with an underlying system error. + /// - propertyListSerializationFailed: Property list serialization failed with an underlying system error. + public enum ResponseSerializationFailureReason { + case inputDataNil + case inputDataNilOrZeroLength + case inputFileNil + case inputFileReadFailed(at: URL) + case stringSerializationFailed(encoding: String.Encoding) + case jsonSerializationFailed(error: Error) + case propertyListSerializationFailed(error: Error) + } + + case invalidURL(url: URLConvertible) + case parameterEncodingFailed(reason: ParameterEncodingFailureReason) + case multipartEncodingFailed(reason: MultipartEncodingFailureReason) + case responseValidationFailed(reason: ResponseValidationFailureReason) + case responseSerializationFailed(reason: ResponseSerializationFailureReason) +} + +// MARK: - Adapt Error + +struct AdaptError: Error { + let error: Error +} + +extension Error { + var underlyingAdaptError: Error? { return (self as? AdaptError)?.error } +} + +// MARK: - Error Booleans + +extension AFError { + /// Returns whether the AFError is an invalid URL error. + public var isInvalidURLError: Bool { + if case .invalidURL = self { return true } + return false + } + + /// Returns whether the AFError is a parameter encoding error. When `true`, the `underlyingError` property will + /// contain the associated value. + public var isParameterEncodingError: Bool { + if case .parameterEncodingFailed = self { return true } + return false + } + + /// Returns whether the AFError is a multipart encoding error. When `true`, the `url` and `underlyingError` properties + /// will contain the associated values. + public var isMultipartEncodingError: Bool { + if case .multipartEncodingFailed = self { return true } + return false + } + + /// Returns whether the `AFError` is a response validation error. When `true`, the `acceptableContentTypes`, + /// `responseContentType`, and `responseCode` properties will contain the associated values. + public var isResponseValidationError: Bool { + if case .responseValidationFailed = self { return true } + return false + } + + /// Returns whether the `AFError` is a response serialization error. When `true`, the `failedStringEncoding` and + /// `underlyingError` properties will contain the associated values. + public var isResponseSerializationError: Bool { + if case .responseSerializationFailed = self { return true } + return false + } +} + +// MARK: - Convenience Properties + +extension AFError { + /// The `URLConvertible` associated with the error. + public var urlConvertible: URLConvertible? { + switch self { + case .invalidURL(let url): + return url + default: + return nil + } + } + + /// The `URL` associated with the error. + public var url: URL? { + switch self { + case .multipartEncodingFailed(let reason): + return reason.url + default: + return nil + } + } + + /// The `Error` returned by a system framework associated with a `.parameterEncodingFailed`, + /// `.multipartEncodingFailed` or `.responseSerializationFailed` error. + public var underlyingError: Error? { + switch self { + case .parameterEncodingFailed(let reason): + return reason.underlyingError + case .multipartEncodingFailed(let reason): + return reason.underlyingError + case .responseSerializationFailed(let reason): + return reason.underlyingError + default: + return nil + } + } + + /// The acceptable `Content-Type`s of a `.responseValidationFailed` error. + public var acceptableContentTypes: [String]? { + switch self { + case .responseValidationFailed(let reason): + return reason.acceptableContentTypes + default: + return nil + } + } + + /// The response `Content-Type` of a `.responseValidationFailed` error. + public var responseContentType: String? { + switch self { + case .responseValidationFailed(let reason): + return reason.responseContentType + default: + return nil + } + } + + /// The response code of a `.responseValidationFailed` error. + public var responseCode: Int? { + switch self { + case .responseValidationFailed(let reason): + return reason.responseCode + default: + return nil + } + } + + /// The `String.Encoding` associated with a failed `.stringResponse()` call. + public var failedStringEncoding: String.Encoding? { + switch self { + case .responseSerializationFailed(let reason): + return reason.failedStringEncoding + default: + return nil + } + } +} + +extension AFError.ParameterEncodingFailureReason { + var underlyingError: Error? { + switch self { + case .jsonEncodingFailed(let error), .propertyListEncodingFailed(let error): + return error + default: + return nil + } + } +} + +extension AFError.MultipartEncodingFailureReason { + var url: URL? { + switch self { + case .bodyPartURLInvalid(let url), .bodyPartFilenameInvalid(let url), .bodyPartFileNotReachable(let url), + .bodyPartFileIsDirectory(let url), .bodyPartFileSizeNotAvailable(let url), + .bodyPartInputStreamCreationFailed(let url), .outputStreamCreationFailed(let url), + .outputStreamFileAlreadyExists(let url), .outputStreamURLInvalid(let url), + .bodyPartFileNotReachableWithError(let url, _), .bodyPartFileSizeQueryFailedWithError(let url, _): + return url + default: + return nil + } + } + + var underlyingError: Error? { + switch self { + case .bodyPartFileNotReachableWithError(_, let error), .bodyPartFileSizeQueryFailedWithError(_, let error), + .outputStreamWriteFailed(let error), .inputStreamReadFailed(let error): + return error + default: + return nil + } + } +} + +extension AFError.ResponseValidationFailureReason { + var acceptableContentTypes: [String]? { + switch self { + case .missingContentType(let types), .unacceptableContentType(let types, _): + return types + default: + return nil + } + } + + var responseContentType: String? { + switch self { + case .unacceptableContentType(_, let responseType): + return responseType + default: + return nil + } + } + + var responseCode: Int? { + switch self { + case .unacceptableStatusCode(let code): + return code + default: + return nil + } + } +} + +extension AFError.ResponseSerializationFailureReason { + var failedStringEncoding: String.Encoding? { + switch self { + case .stringSerializationFailed(let encoding): + return encoding + default: + return nil + } + } + + var underlyingError: Error? { + switch self { + case .jsonSerializationFailed(let error), .propertyListSerializationFailed(let error): + return error + default: + return nil + } + } +} + +// MARK: - Error Descriptions + +extension AFError: LocalizedError { + public var errorDescription: String? { + switch self { + case .invalidURL(let url): + return "URL is not valid: \(url)" + case .parameterEncodingFailed(let reason): + return reason.localizedDescription + case .multipartEncodingFailed(let reason): + return reason.localizedDescription + case .responseValidationFailed(let reason): + return reason.localizedDescription + case .responseSerializationFailed(let reason): + return reason.localizedDescription + } + } +} + +extension AFError.ParameterEncodingFailureReason { + var localizedDescription: String { + switch self { + case .missingURL: + return "URL request to encode was missing a URL" + case .jsonEncodingFailed(let error): + return "JSON could not be encoded because of error:\n\(error.localizedDescription)" + case .propertyListEncodingFailed(let error): + return "PropertyList could not be encoded because of error:\n\(error.localizedDescription)" + } + } +} + +extension AFError.MultipartEncodingFailureReason { + var localizedDescription: String { + switch self { + case .bodyPartURLInvalid(let url): + return "The URL provided is not a file URL: \(url)" + case .bodyPartFilenameInvalid(let url): + return "The URL provided does not have a valid filename: \(url)" + case .bodyPartFileNotReachable(let url): + return "The URL provided is not reachable: \(url)" + case .bodyPartFileNotReachableWithError(let url, let error): + return ( + "The system returned an error while checking the provided URL for " + + "reachability.\nURL: \(url)\nError: \(error)" + ) + case .bodyPartFileIsDirectory(let url): + return "The URL provided is a directory: \(url)" + case .bodyPartFileSizeNotAvailable(let url): + return "Could not fetch the file size from the provided URL: \(url)" + case .bodyPartFileSizeQueryFailedWithError(let url, let error): + return ( + "The system returned an error while attempting to fetch the file size from the " + + "provided URL.\nURL: \(url)\nError: \(error)" + ) + case .bodyPartInputStreamCreationFailed(let url): + return "Failed to create an InputStream for the provided URL: \(url)" + case .outputStreamCreationFailed(let url): + return "Failed to create an OutputStream for URL: \(url)" + case .outputStreamFileAlreadyExists(let url): + return "A file already exists at the provided URL: \(url)" + case .outputStreamURLInvalid(let url): + return "The provided OutputStream URL is invalid: \(url)" + case .outputStreamWriteFailed(let error): + return "OutputStream write failed with error: \(error)" + case .inputStreamReadFailed(let error): + return "InputStream read failed with error: \(error)" + } + } +} + +extension AFError.ResponseSerializationFailureReason { + var localizedDescription: String { + switch self { + case .inputDataNil: + return "Response could not be serialized, input data was nil." + case .inputDataNilOrZeroLength: + return "Response could not be serialized, input data was nil or zero length." + case .inputFileNil: + return "Response could not be serialized, input file was nil." + case .inputFileReadFailed(let url): + return "Response could not be serialized, input file could not be read: \(url)." + case .stringSerializationFailed(let encoding): + return "String could not be serialized with encoding: \(encoding)." + case .jsonSerializationFailed(let error): + return "JSON could not be serialized because of error:\n\(error.localizedDescription)" + case .propertyListSerializationFailed(let error): + return "PropertyList could not be serialized because of error:\n\(error.localizedDescription)" + } + } +} + +extension AFError.ResponseValidationFailureReason { + var localizedDescription: String { + switch self { + case .dataFileNil: + return "Response could not be validated, data file was nil." + case .dataFileReadFailed(let url): + return "Response could not be validated, data file could not be read: \(url)." + case .missingContentType(let types): + return ( + "Response Content-Type was missing and acceptable content types " + + "(\(types.joined(separator: ","))) do not match \"*/*\"." + ) + case .unacceptableContentType(let acceptableTypes, let responseType): + return ( + "Response Content-Type \"\(responseType)\" does not match any acceptable types: " + + "\(acceptableTypes.joined(separator: ","))." + ) + case .unacceptableStatusCode(let code): + return "Response status code was unacceptable: \(code)." + } + } +} diff --git a/Pods/Alamofire/Source/Alamofire.swift b/Pods/Alamofire/Source/Alamofire.swift new file mode 100644 index 0000000..20c3672 --- /dev/null +++ b/Pods/Alamofire/Source/Alamofire.swift @@ -0,0 +1,465 @@ +// +// Alamofire.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// Types adopting the `URLConvertible` protocol can be used to construct URLs, which are then used to construct +/// URL requests. +public protocol URLConvertible { + /// Returns a URL that conforms to RFC 2396 or throws an `Error`. + /// + /// - throws: An `Error` if the type cannot be converted to a `URL`. + /// + /// - returns: A URL or throws an `Error`. + func asURL() throws -> URL +} + +extension String: URLConvertible { + /// Returns a URL if `self` represents a valid URL string that conforms to RFC 2396 or throws an `AFError`. + /// + /// - throws: An `AFError.invalidURL` if `self` is not a valid URL string. + /// + /// - returns: A URL or throws an `AFError`. + public func asURL() throws -> URL { + guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) } + return url + } +} + +extension URL: URLConvertible { + /// Returns self. + public func asURL() throws -> URL { return self } +} + +extension URLComponents: URLConvertible { + /// Returns a URL if `url` is not nil, otherwise throws an `Error`. + /// + /// - throws: An `AFError.invalidURL` if `url` is `nil`. + /// + /// - returns: A URL or throws an `AFError`. + public func asURL() throws -> URL { + guard let url = url else { throw AFError.invalidURL(url: self) } + return url + } +} + +// MARK: - + +/// Types adopting the `URLRequestConvertible` protocol can be used to construct URL requests. +public protocol URLRequestConvertible { + /// Returns a URL request or throws if an `Error` was encountered. + /// + /// - throws: An `Error` if the underlying `URLRequest` is `nil`. + /// + /// - returns: A URL request. + func asURLRequest() throws -> URLRequest +} + +extension URLRequestConvertible { + /// The URL request. + public var urlRequest: URLRequest? { return try? asURLRequest() } +} + +extension URLRequest: URLRequestConvertible { + /// Returns a URL request or throws if an `Error` was encountered. + public func asURLRequest() throws -> URLRequest { return self } +} + +// MARK: - + +extension URLRequest { + /// Creates an instance with the specified `method`, `urlString` and `headers`. + /// + /// - parameter url: The URL. + /// - parameter method: The HTTP method. + /// - parameter headers: The HTTP headers. `nil` by default. + /// + /// - returns: The new `URLRequest` instance. + public init(url: URLConvertible, method: HTTPMethod, headers: HTTPHeaders? = nil) throws { + let url = try url.asURL() + + self.init(url: url) + + httpMethod = method.rawValue + + if let headers = headers { + for (headerField, headerValue) in headers { + setValue(headerValue, forHTTPHeaderField: headerField) + } + } + } + + func adapt(using adapter: RequestAdapter?) throws -> URLRequest { + guard let adapter = adapter else { return self } + return try adapter.adapt(self) + } +} + +// MARK: - Data Request + +/// Creates a `DataRequest` using the default `SessionManager` to retrieve the contents of the specified `url`, +/// `method`, `parameters`, `encoding` and `headers`. +/// +/// - parameter url: The URL. +/// - parameter method: The HTTP method. `.get` by default. +/// - parameter parameters: The parameters. `nil` by default. +/// - parameter encoding: The parameter encoding. `URLEncoding.default` by default. +/// - parameter headers: The HTTP headers. `nil` by default. +/// +/// - returns: The created `DataRequest`. +@discardableResult +public func request( + _ url: URLConvertible, + method: HTTPMethod = .get, + parameters: Parameters? = nil, + encoding: ParameterEncoding = URLEncoding.default, + headers: HTTPHeaders? = nil) + -> DataRequest +{ + return SessionManager.default.request( + url, + method: method, + parameters: parameters, + encoding: encoding, + headers: headers + ) +} + +/// Creates a `DataRequest` using the default `SessionManager` to retrieve the contents of a URL based on the +/// specified `urlRequest`. +/// +/// - parameter urlRequest: The URL request +/// +/// - returns: The created `DataRequest`. +@discardableResult +public func request(_ urlRequest: URLRequestConvertible) -> DataRequest { + return SessionManager.default.request(urlRequest) +} + +// MARK: - Download Request + +// MARK: URL Request + +/// Creates a `DownloadRequest` using the default `SessionManager` to retrieve the contents of the specified `url`, +/// `method`, `parameters`, `encoding`, `headers` and save them to the `destination`. +/// +/// If `destination` is not specified, the contents will remain in the temporary location determined by the +/// underlying URL session. +/// +/// - parameter url: The URL. +/// - parameter method: The HTTP method. `.get` by default. +/// - parameter parameters: The parameters. `nil` by default. +/// - parameter encoding: The parameter encoding. `URLEncoding.default` by default. +/// - parameter headers: The HTTP headers. `nil` by default. +/// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default. +/// +/// - returns: The created `DownloadRequest`. +@discardableResult +public func download( + _ url: URLConvertible, + method: HTTPMethod = .get, + parameters: Parameters? = nil, + encoding: ParameterEncoding = URLEncoding.default, + headers: HTTPHeaders? = nil, + to destination: DownloadRequest.DownloadFileDestination? = nil) + -> DownloadRequest +{ + return SessionManager.default.download( + url, + method: method, + parameters: parameters, + encoding: encoding, + headers: headers, + to: destination + ) +} + +/// Creates a `DownloadRequest` using the default `SessionManager` to retrieve the contents of a URL based on the +/// specified `urlRequest` and save them to the `destination`. +/// +/// If `destination` is not specified, the contents will remain in the temporary location determined by the +/// underlying URL session. +/// +/// - parameter urlRequest: The URL request. +/// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default. +/// +/// - returns: The created `DownloadRequest`. +@discardableResult +public func download( + _ urlRequest: URLRequestConvertible, + to destination: DownloadRequest.DownloadFileDestination? = nil) + -> DownloadRequest +{ + return SessionManager.default.download(urlRequest, to: destination) +} + +// MARK: Resume Data + +/// Creates a `DownloadRequest` using the default `SessionManager` from the `resumeData` produced from a +/// previous request cancellation to retrieve the contents of the original request and save them to the `destination`. +/// +/// If `destination` is not specified, the contents will remain in the temporary location determined by the +/// underlying URL session. +/// +/// On the latest release of all the Apple platforms (iOS 10, macOS 10.12, tvOS 10, watchOS 3), `resumeData` is broken +/// on background URL session configurations. There's an underlying bug in the `resumeData` generation logic where the +/// data is written incorrectly and will always fail to resume the download. For more information about the bug and +/// possible workarounds, please refer to the following Stack Overflow post: +/// +/// - http://stackoverflow.com/a/39347461/1342462 +/// +/// - parameter resumeData: The resume data. This is an opaque data blob produced by `URLSessionDownloadTask` +/// when a task is cancelled. See `URLSession -downloadTask(withResumeData:)` for additional +/// information. +/// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default. +/// +/// - returns: The created `DownloadRequest`. +@discardableResult +public func download( + resumingWith resumeData: Data, + to destination: DownloadRequest.DownloadFileDestination? = nil) + -> DownloadRequest +{ + return SessionManager.default.download(resumingWith: resumeData, to: destination) +} + +// MARK: - Upload Request + +// MARK: File + +/// Creates an `UploadRequest` using the default `SessionManager` from the specified `url`, `method` and `headers` +/// for uploading the `file`. +/// +/// - parameter file: The file to upload. +/// - parameter url: The URL. +/// - parameter method: The HTTP method. `.post` by default. +/// - parameter headers: The HTTP headers. `nil` by default. +/// +/// - returns: The created `UploadRequest`. +@discardableResult +public func upload( + _ fileURL: URL, + to url: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil) + -> UploadRequest +{ + return SessionManager.default.upload(fileURL, to: url, method: method, headers: headers) +} + +/// Creates a `UploadRequest` using the default `SessionManager` from the specified `urlRequest` for +/// uploading the `file`. +/// +/// - parameter file: The file to upload. +/// - parameter urlRequest: The URL request. +/// +/// - returns: The created `UploadRequest`. +@discardableResult +public func upload(_ fileURL: URL, with urlRequest: URLRequestConvertible) -> UploadRequest { + return SessionManager.default.upload(fileURL, with: urlRequest) +} + +// MARK: Data + +/// Creates an `UploadRequest` using the default `SessionManager` from the specified `url`, `method` and `headers` +/// for uploading the `data`. +/// +/// - parameter data: The data to upload. +/// - parameter url: The URL. +/// - parameter method: The HTTP method. `.post` by default. +/// - parameter headers: The HTTP headers. `nil` by default. +/// +/// - returns: The created `UploadRequest`. +@discardableResult +public func upload( + _ data: Data, + to url: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil) + -> UploadRequest +{ + return SessionManager.default.upload(data, to: url, method: method, headers: headers) +} + +/// Creates an `UploadRequest` using the default `SessionManager` from the specified `urlRequest` for +/// uploading the `data`. +/// +/// - parameter data: The data to upload. +/// - parameter urlRequest: The URL request. +/// +/// - returns: The created `UploadRequest`. +@discardableResult +public func upload(_ data: Data, with urlRequest: URLRequestConvertible) -> UploadRequest { + return SessionManager.default.upload(data, with: urlRequest) +} + +// MARK: InputStream + +/// Creates an `UploadRequest` using the default `SessionManager` from the specified `url`, `method` and `headers` +/// for uploading the `stream`. +/// +/// - parameter stream: The stream to upload. +/// - parameter url: The URL. +/// - parameter method: The HTTP method. `.post` by default. +/// - parameter headers: The HTTP headers. `nil` by default. +/// +/// - returns: The created `UploadRequest`. +@discardableResult +public func upload( + _ stream: InputStream, + to url: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil) + -> UploadRequest +{ + return SessionManager.default.upload(stream, to: url, method: method, headers: headers) +} + +/// Creates an `UploadRequest` using the default `SessionManager` from the specified `urlRequest` for +/// uploading the `stream`. +/// +/// - parameter urlRequest: The URL request. +/// - parameter stream: The stream to upload. +/// +/// - returns: The created `UploadRequest`. +@discardableResult +public func upload(_ stream: InputStream, with urlRequest: URLRequestConvertible) -> UploadRequest { + return SessionManager.default.upload(stream, with: urlRequest) +} + +// MARK: MultipartFormData + +/// Encodes `multipartFormData` using `encodingMemoryThreshold` with the default `SessionManager` and calls +/// `encodingCompletion` with new `UploadRequest` using the `url`, `method` and `headers`. +/// +/// It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative +/// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most +/// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to +/// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory +/// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be +/// used for larger payloads such as video content. +/// +/// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory +/// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`, +/// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk +/// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding +/// technique was used. +/// +/// - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`. +/// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes. +/// `multipartFormDataEncodingMemoryThreshold` by default. +/// - parameter url: The URL. +/// - parameter method: The HTTP method. `.post` by default. +/// - parameter headers: The HTTP headers. `nil` by default. +/// - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete. +public func upload( + multipartFormData: @escaping (MultipartFormData) -> Void, + usingThreshold encodingMemoryThreshold: UInt64 = SessionManager.multipartFormDataEncodingMemoryThreshold, + to url: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil, + encodingCompletion: ((SessionManager.MultipartFormDataEncodingResult) -> Void)?) +{ + return SessionManager.default.upload( + multipartFormData: multipartFormData, + usingThreshold: encodingMemoryThreshold, + to: url, + method: method, + headers: headers, + encodingCompletion: encodingCompletion + ) +} + +/// Encodes `multipartFormData` using `encodingMemoryThreshold` and the default `SessionManager` and +/// calls `encodingCompletion` with new `UploadRequest` using the `urlRequest`. +/// +/// It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative +/// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most +/// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to +/// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory +/// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be +/// used for larger payloads such as video content. +/// +/// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory +/// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`, +/// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk +/// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding +/// technique was used. +/// +/// - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`. +/// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes. +/// `multipartFormDataEncodingMemoryThreshold` by default. +/// - parameter urlRequest: The URL request. +/// - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete. +public func upload( + multipartFormData: @escaping (MultipartFormData) -> Void, + usingThreshold encodingMemoryThreshold: UInt64 = SessionManager.multipartFormDataEncodingMemoryThreshold, + with urlRequest: URLRequestConvertible, + encodingCompletion: ((SessionManager.MultipartFormDataEncodingResult) -> Void)?) +{ + return SessionManager.default.upload( + multipartFormData: multipartFormData, + usingThreshold: encodingMemoryThreshold, + with: urlRequest, + encodingCompletion: encodingCompletion + ) +} + +#if !os(watchOS) + +// MARK: - Stream Request + +// MARK: Hostname and Port + +/// Creates a `StreamRequest` using the default `SessionManager` for bidirectional streaming with the `hostname` +/// and `port`. +/// +/// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. +/// +/// - parameter hostName: The hostname of the server to connect to. +/// - parameter port: The port of the server to connect to. +/// +/// - returns: The created `StreamRequest`. +@discardableResult +@available(iOS 9.0, macOS 10.11, tvOS 9.0, *) +public func stream(withHostName hostName: String, port: Int) -> StreamRequest { + return SessionManager.default.stream(withHostName: hostName, port: port) +} + +// MARK: NetService + +/// Creates a `StreamRequest` using the default `SessionManager` for bidirectional streaming with the `netService`. +/// +/// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. +/// +/// - parameter netService: The net service used to identify the endpoint. +/// +/// - returns: The created `StreamRequest`. +@discardableResult +@available(iOS 9.0, macOS 10.11, tvOS 9.0, *) +public func stream(with netService: NetService) -> StreamRequest { + return SessionManager.default.stream(with: netService) +} + +#endif diff --git a/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift b/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift new file mode 100644 index 0000000..a54673c --- /dev/null +++ b/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift @@ -0,0 +1,37 @@ +// +// DispatchQueue+Alamofire.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Dispatch +import Foundation + +extension DispatchQueue { + static var userInteractive: DispatchQueue { return DispatchQueue.global(qos: .userInteractive) } + static var userInitiated: DispatchQueue { return DispatchQueue.global(qos: .userInitiated) } + static var utility: DispatchQueue { return DispatchQueue.global(qos: .utility) } + static var background: DispatchQueue { return DispatchQueue.global(qos: .background) } + + func after(_ delay: TimeInterval, execute closure: @escaping () -> Void) { + asyncAfter(deadline: .now() + delay, execute: closure) + } +} diff --git a/Pods/Alamofire/Source/MultipartFormData.swift b/Pods/Alamofire/Source/MultipartFormData.swift new file mode 100644 index 0000000..b840138 --- /dev/null +++ b/Pods/Alamofire/Source/MultipartFormData.swift @@ -0,0 +1,580 @@ +// +// MultipartFormData.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +#if os(iOS) || os(watchOS) || os(tvOS) +import MobileCoreServices +#elseif os(macOS) +import CoreServices +#endif + +/// Constructs `multipart/form-data` for uploads within an HTTP or HTTPS body. There are currently two ways to encode +/// multipart form data. The first way is to encode the data directly in memory. This is very efficient, but can lead +/// to memory issues if the dataset is too large. The second way is designed for larger datasets and will write all the +/// data to a single file on disk with all the proper boundary segmentation. The second approach MUST be used for +/// larger datasets such as video content, otherwise your app may run out of memory when trying to encode the dataset. +/// +/// For more information on `multipart/form-data` in general, please refer to the RFC-2388 and RFC-2045 specs as well +/// and the w3 form documentation. +/// +/// - https://www.ietf.org/rfc/rfc2388.txt +/// - https://www.ietf.org/rfc/rfc2045.txt +/// - https://www.w3.org/TR/html401/interact/forms.html#h-17.13 +open class MultipartFormData { + + // MARK: - Helper Types + + struct EncodingCharacters { + static let crlf = "\r\n" + } + + struct BoundaryGenerator { + enum BoundaryType { + case initial, encapsulated, final + } + + static func randomBoundary() -> String { + return String(format: "alamofire.boundary.%08x%08x", arc4random(), arc4random()) + } + + static func boundaryData(forBoundaryType boundaryType: BoundaryType, boundary: String) -> Data { + let boundaryText: String + + switch boundaryType { + case .initial: + boundaryText = "--\(boundary)\(EncodingCharacters.crlf)" + case .encapsulated: + boundaryText = "\(EncodingCharacters.crlf)--\(boundary)\(EncodingCharacters.crlf)" + case .final: + boundaryText = "\(EncodingCharacters.crlf)--\(boundary)--\(EncodingCharacters.crlf)" + } + + return boundaryText.data(using: String.Encoding.utf8, allowLossyConversion: false)! + } + } + + class BodyPart { + let headers: HTTPHeaders + let bodyStream: InputStream + let bodyContentLength: UInt64 + var hasInitialBoundary = false + var hasFinalBoundary = false + + init(headers: HTTPHeaders, bodyStream: InputStream, bodyContentLength: UInt64) { + self.headers = headers + self.bodyStream = bodyStream + self.bodyContentLength = bodyContentLength + } + } + + // MARK: - Properties + + /// The `Content-Type` header value containing the boundary used to generate the `multipart/form-data`. + open lazy var contentType: String = "multipart/form-data; boundary=\(self.boundary)" + + /// The content length of all body parts used to generate the `multipart/form-data` not including the boundaries. + public var contentLength: UInt64 { return bodyParts.reduce(0) { $0 + $1.bodyContentLength } } + + /// The boundary used to separate the body parts in the encoded form data. + public var boundary: String + + private var bodyParts: [BodyPart] + private var bodyPartError: AFError? + private let streamBufferSize: Int + + // MARK: - Lifecycle + + /// Creates a multipart form data object. + /// + /// - returns: The multipart form data object. + public init() { + self.boundary = BoundaryGenerator.randomBoundary() + self.bodyParts = [] + + /// + /// The optimal read/write buffer size in bytes for input and output streams is 1024 (1KB). For more + /// information, please refer to the following article: + /// - https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html + /// + + self.streamBufferSize = 1024 + } + + // MARK: - Body Parts + + /// Creates a body part from the data and appends it to the multipart form data object. + /// + /// The body part data will be encoded using the following format: + /// + /// - `Content-Disposition: form-data; name=#{name}` (HTTP Header) + /// - Encoded data + /// - Multipart form boundary + /// + /// - parameter data: The data to encode into the multipart form data. + /// - parameter name: The name to associate with the data in the `Content-Disposition` HTTP header. + public func append(_ data: Data, withName name: String) { + let headers = contentHeaders(withName: name) + let stream = InputStream(data: data) + let length = UInt64(data.count) + + append(stream, withLength: length, headers: headers) + } + + /// Creates a body part from the data and appends it to the multipart form data object. + /// + /// The body part data will be encoded using the following format: + /// + /// - `Content-Disposition: form-data; name=#{name}` (HTTP Header) + /// - `Content-Type: #{generated mimeType}` (HTTP Header) + /// - Encoded data + /// - Multipart form boundary + /// + /// - parameter data: The data to encode into the multipart form data. + /// - parameter name: The name to associate with the data in the `Content-Disposition` HTTP header. + /// - parameter mimeType: The MIME type to associate with the data content type in the `Content-Type` HTTP header. + public func append(_ data: Data, withName name: String, mimeType: String) { + let headers = contentHeaders(withName: name, mimeType: mimeType) + let stream = InputStream(data: data) + let length = UInt64(data.count) + + append(stream, withLength: length, headers: headers) + } + + /// Creates a body part from the data and appends it to the multipart form data object. + /// + /// The body part data will be encoded using the following format: + /// + /// - `Content-Disposition: form-data; name=#{name}; filename=#{filename}` (HTTP Header) + /// - `Content-Type: #{mimeType}` (HTTP Header) + /// - Encoded file data + /// - Multipart form boundary + /// + /// - parameter data: The data to encode into the multipart form data. + /// - parameter name: The name to associate with the data in the `Content-Disposition` HTTP header. + /// - parameter fileName: The filename to associate with the data in the `Content-Disposition` HTTP header. + /// - parameter mimeType: The MIME type to associate with the data in the `Content-Type` HTTP header. + public func append(_ data: Data, withName name: String, fileName: String, mimeType: String) { + let headers = contentHeaders(withName: name, fileName: fileName, mimeType: mimeType) + let stream = InputStream(data: data) + let length = UInt64(data.count) + + append(stream, withLength: length, headers: headers) + } + + /// Creates a body part from the file and appends it to the multipart form data object. + /// + /// The body part data will be encoded using the following format: + /// + /// - `Content-Disposition: form-data; name=#{name}; filename=#{generated filename}` (HTTP Header) + /// - `Content-Type: #{generated mimeType}` (HTTP Header) + /// - Encoded file data + /// - Multipart form boundary + /// + /// The filename in the `Content-Disposition` HTTP header is generated from the last path component of the + /// `fileURL`. The `Content-Type` HTTP header MIME type is generated by mapping the `fileURL` extension to the + /// system associated MIME type. + /// + /// - parameter fileURL: The URL of the file whose content will be encoded into the multipart form data. + /// - parameter name: The name to associate with the file content in the `Content-Disposition` HTTP header. + public func append(_ fileURL: URL, withName name: String) { + let fileName = fileURL.lastPathComponent + let pathExtension = fileURL.pathExtension + + if !fileName.isEmpty && !pathExtension.isEmpty { + let mime = mimeType(forPathExtension: pathExtension) + append(fileURL, withName: name, fileName: fileName, mimeType: mime) + } else { + setBodyPartError(withReason: .bodyPartFilenameInvalid(in: fileURL)) + } + } + + /// Creates a body part from the file and appends it to the multipart form data object. + /// + /// The body part data will be encoded using the following format: + /// + /// - Content-Disposition: form-data; name=#{name}; filename=#{filename} (HTTP Header) + /// - Content-Type: #{mimeType} (HTTP Header) + /// - Encoded file data + /// - Multipart form boundary + /// + /// - parameter fileURL: The URL of the file whose content will be encoded into the multipart form data. + /// - parameter name: The name to associate with the file content in the `Content-Disposition` HTTP header. + /// - parameter fileName: The filename to associate with the file content in the `Content-Disposition` HTTP header. + /// - parameter mimeType: The MIME type to associate with the file content in the `Content-Type` HTTP header. + public func append(_ fileURL: URL, withName name: String, fileName: String, mimeType: String) { + let headers = contentHeaders(withName: name, fileName: fileName, mimeType: mimeType) + + //============================================================ + // Check 1 - is file URL? + //============================================================ + + guard fileURL.isFileURL else { + setBodyPartError(withReason: .bodyPartURLInvalid(url: fileURL)) + return + } + + //============================================================ + // Check 2 - is file URL reachable? + //============================================================ + + do { + let isReachable = try fileURL.checkPromisedItemIsReachable() + guard isReachable else { + setBodyPartError(withReason: .bodyPartFileNotReachable(at: fileURL)) + return + } + } catch { + setBodyPartError(withReason: .bodyPartFileNotReachableWithError(atURL: fileURL, error: error)) + return + } + + //============================================================ + // Check 3 - is file URL a directory? + //============================================================ + + var isDirectory: ObjCBool = false + let path = fileURL.path + + guard FileManager.default.fileExists(atPath: path, isDirectory: &isDirectory) && !isDirectory.boolValue else { + setBodyPartError(withReason: .bodyPartFileIsDirectory(at: fileURL)) + return + } + + //============================================================ + // Check 4 - can the file size be extracted? + //============================================================ + + let bodyContentLength: UInt64 + + do { + guard let fileSize = try FileManager.default.attributesOfItem(atPath: path)[.size] as? NSNumber else { + setBodyPartError(withReason: .bodyPartFileSizeNotAvailable(at: fileURL)) + return + } + + bodyContentLength = fileSize.uint64Value + } + catch { + setBodyPartError(withReason: .bodyPartFileSizeQueryFailedWithError(forURL: fileURL, error: error)) + return + } + + //============================================================ + // Check 5 - can a stream be created from file URL? + //============================================================ + + guard let stream = InputStream(url: fileURL) else { + setBodyPartError(withReason: .bodyPartInputStreamCreationFailed(for: fileURL)) + return + } + + append(stream, withLength: bodyContentLength, headers: headers) + } + + /// Creates a body part from the stream and appends it to the multipart form data object. + /// + /// The body part data will be encoded using the following format: + /// + /// - `Content-Disposition: form-data; name=#{name}; filename=#{filename}` (HTTP Header) + /// - `Content-Type: #{mimeType}` (HTTP Header) + /// - Encoded stream data + /// - Multipart form boundary + /// + /// - parameter stream: The input stream to encode in the multipart form data. + /// - parameter length: The content length of the stream. + /// - parameter name: The name to associate with the stream content in the `Content-Disposition` HTTP header. + /// - parameter fileName: The filename to associate with the stream content in the `Content-Disposition` HTTP header. + /// - parameter mimeType: The MIME type to associate with the stream content in the `Content-Type` HTTP header. + public func append( + _ stream: InputStream, + withLength length: UInt64, + name: String, + fileName: String, + mimeType: String) + { + let headers = contentHeaders(withName: name, fileName: fileName, mimeType: mimeType) + append(stream, withLength: length, headers: headers) + } + + /// Creates a body part with the headers, stream and length and appends it to the multipart form data object. + /// + /// The body part data will be encoded using the following format: + /// + /// - HTTP headers + /// - Encoded stream data + /// - Multipart form boundary + /// + /// - parameter stream: The input stream to encode in the multipart form data. + /// - parameter length: The content length of the stream. + /// - parameter headers: The HTTP headers for the body part. + public func append(_ stream: InputStream, withLength length: UInt64, headers: HTTPHeaders) { + let bodyPart = BodyPart(headers: headers, bodyStream: stream, bodyContentLength: length) + bodyParts.append(bodyPart) + } + + // MARK: - Data Encoding + + /// Encodes all the appended body parts into a single `Data` value. + /// + /// It is important to note that this method will load all the appended body parts into memory all at the same + /// time. This method should only be used when the encoded data will have a small memory footprint. For large data + /// cases, please use the `writeEncodedDataToDisk(fileURL:completionHandler:)` method. + /// + /// - throws: An `AFError` if encoding encounters an error. + /// + /// - returns: The encoded `Data` if encoding is successful. + public func encode() throws -> Data { + if let bodyPartError = bodyPartError { + throw bodyPartError + } + + var encoded = Data() + + bodyParts.first?.hasInitialBoundary = true + bodyParts.last?.hasFinalBoundary = true + + for bodyPart in bodyParts { + let encodedData = try encode(bodyPart) + encoded.append(encodedData) + } + + return encoded + } + + /// Writes the appended body parts into the given file URL. + /// + /// This process is facilitated by reading and writing with input and output streams, respectively. Thus, + /// this approach is very memory efficient and should be used for large body part data. + /// + /// - parameter fileURL: The file URL to write the multipart form data into. + /// + /// - throws: An `AFError` if encoding encounters an error. + public func writeEncodedData(to fileURL: URL) throws { + if let bodyPartError = bodyPartError { + throw bodyPartError + } + + if FileManager.default.fileExists(atPath: fileURL.path) { + throw AFError.multipartEncodingFailed(reason: .outputStreamFileAlreadyExists(at: fileURL)) + } else if !fileURL.isFileURL { + throw AFError.multipartEncodingFailed(reason: .outputStreamURLInvalid(url: fileURL)) + } + + guard let outputStream = OutputStream(url: fileURL, append: false) else { + throw AFError.multipartEncodingFailed(reason: .outputStreamCreationFailed(for: fileURL)) + } + + outputStream.open() + defer { outputStream.close() } + + self.bodyParts.first?.hasInitialBoundary = true + self.bodyParts.last?.hasFinalBoundary = true + + for bodyPart in self.bodyParts { + try write(bodyPart, to: outputStream) + } + } + + // MARK: - Private - Body Part Encoding + + private func encode(_ bodyPart: BodyPart) throws -> Data { + var encoded = Data() + + let initialData = bodyPart.hasInitialBoundary ? initialBoundaryData() : encapsulatedBoundaryData() + encoded.append(initialData) + + let headerData = encodeHeaders(for: bodyPart) + encoded.append(headerData) + + let bodyStreamData = try encodeBodyStream(for: bodyPart) + encoded.append(bodyStreamData) + + if bodyPart.hasFinalBoundary { + encoded.append(finalBoundaryData()) + } + + return encoded + } + + private func encodeHeaders(for bodyPart: BodyPart) -> Data { + var headerText = "" + + for (key, value) in bodyPart.headers { + headerText += "\(key): \(value)\(EncodingCharacters.crlf)" + } + headerText += EncodingCharacters.crlf + + return headerText.data(using: String.Encoding.utf8, allowLossyConversion: false)! + } + + private func encodeBodyStream(for bodyPart: BodyPart) throws -> Data { + let inputStream = bodyPart.bodyStream + inputStream.open() + defer { inputStream.close() } + + var encoded = Data() + + while inputStream.hasBytesAvailable { + var buffer = [UInt8](repeating: 0, count: streamBufferSize) + let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize) + + if let error = inputStream.streamError { + throw AFError.multipartEncodingFailed(reason: .inputStreamReadFailed(error: error)) + } + + if bytesRead > 0 { + encoded.append(buffer, count: bytesRead) + } else { + break + } + } + + return encoded + } + + // MARK: - Private - Writing Body Part to Output Stream + + private func write(_ bodyPart: BodyPart, to outputStream: OutputStream) throws { + try writeInitialBoundaryData(for: bodyPart, to: outputStream) + try writeHeaderData(for: bodyPart, to: outputStream) + try writeBodyStream(for: bodyPart, to: outputStream) + try writeFinalBoundaryData(for: bodyPart, to: outputStream) + } + + private func writeInitialBoundaryData(for bodyPart: BodyPart, to outputStream: OutputStream) throws { + let initialData = bodyPart.hasInitialBoundary ? initialBoundaryData() : encapsulatedBoundaryData() + return try write(initialData, to: outputStream) + } + + private func writeHeaderData(for bodyPart: BodyPart, to outputStream: OutputStream) throws { + let headerData = encodeHeaders(for: bodyPart) + return try write(headerData, to: outputStream) + } + + private func writeBodyStream(for bodyPart: BodyPart, to outputStream: OutputStream) throws { + let inputStream = bodyPart.bodyStream + + inputStream.open() + defer { inputStream.close() } + + while inputStream.hasBytesAvailable { + var buffer = [UInt8](repeating: 0, count: streamBufferSize) + let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize) + + if let streamError = inputStream.streamError { + throw AFError.multipartEncodingFailed(reason: .inputStreamReadFailed(error: streamError)) + } + + if bytesRead > 0 { + if buffer.count != bytesRead { + buffer = Array(buffer[0.. 0, outputStream.hasSpaceAvailable { + let bytesWritten = outputStream.write(buffer, maxLength: bytesToWrite) + + if let error = outputStream.streamError { + throw AFError.multipartEncodingFailed(reason: .outputStreamWriteFailed(error: error)) + } + + bytesToWrite -= bytesWritten + + if bytesToWrite > 0 { + buffer = Array(buffer[bytesWritten.. String { + if + let id = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(), + let contentType = UTTypeCopyPreferredTagWithClass(id, kUTTagClassMIMEType)?.takeRetainedValue() + { + return contentType as String + } + + return "application/octet-stream" + } + + // MARK: - Private - Content Headers + + private func contentHeaders(withName name: String, fileName: String? = nil, mimeType: String? = nil) -> [String: String] { + var disposition = "form-data; name=\"\(name)\"" + if let fileName = fileName { disposition += "; filename=\"\(fileName)\"" } + + var headers = ["Content-Disposition": disposition] + if let mimeType = mimeType { headers["Content-Type"] = mimeType } + + return headers + } + + // MARK: - Private - Boundary Encoding + + private func initialBoundaryData() -> Data { + return BoundaryGenerator.boundaryData(forBoundaryType: .initial, boundary: boundary) + } + + private func encapsulatedBoundaryData() -> Data { + return BoundaryGenerator.boundaryData(forBoundaryType: .encapsulated, boundary: boundary) + } + + private func finalBoundaryData() -> Data { + return BoundaryGenerator.boundaryData(forBoundaryType: .final, boundary: boundary) + } + + // MARK: - Private - Errors + + private func setBodyPartError(withReason reason: AFError.MultipartEncodingFailureReason) { + guard bodyPartError == nil else { return } + bodyPartError = AFError.multipartEncodingFailed(reason: reason) + } +} diff --git a/Pods/Alamofire/Source/NetworkReachabilityManager.swift b/Pods/Alamofire/Source/NetworkReachabilityManager.swift new file mode 100644 index 0000000..398ca82 --- /dev/null +++ b/Pods/Alamofire/Source/NetworkReachabilityManager.swift @@ -0,0 +1,238 @@ +// +// NetworkReachabilityManager.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#if !os(watchOS) + +import Foundation +import SystemConfiguration + +/// The `NetworkReachabilityManager` class listens for reachability changes of hosts and addresses for both WWAN and +/// WiFi network interfaces. +/// +/// Reachability can be used to determine background information about why a network operation failed, or to retry +/// network requests when a connection is established. It should not be used to prevent a user from initiating a network +/// request, as it's possible that an initial request may be required to establish reachability. +open class NetworkReachabilityManager { + /// Defines the various states of network reachability. + /// + /// - unknown: It is unknown whether the network is reachable. + /// - notReachable: The network is not reachable. + /// - reachable: The network is reachable. + public enum NetworkReachabilityStatus { + case unknown + case notReachable + case reachable(ConnectionType) + } + + /// Defines the various connection types detected by reachability flags. + /// + /// - ethernetOrWiFi: The connection type is either over Ethernet or WiFi. + /// - wwan: The connection type is a WWAN connection. + public enum ConnectionType { + case ethernetOrWiFi + case wwan + } + + /// A closure executed when the network reachability status changes. The closure takes a single argument: the + /// network reachability status. + public typealias Listener = (NetworkReachabilityStatus) -> Void + + // MARK: - Properties + + /// Whether the network is currently reachable. + open var isReachable: Bool { return isReachableOnWWAN || isReachableOnEthernetOrWiFi } + + /// Whether the network is currently reachable over the WWAN interface. + open var isReachableOnWWAN: Bool { return networkReachabilityStatus == .reachable(.wwan) } + + /// Whether the network is currently reachable over Ethernet or WiFi interface. + open var isReachableOnEthernetOrWiFi: Bool { return networkReachabilityStatus == .reachable(.ethernetOrWiFi) } + + /// The current network reachability status. + open var networkReachabilityStatus: NetworkReachabilityStatus { + guard let flags = self.flags else { return .unknown } + return networkReachabilityStatusForFlags(flags) + } + + /// The dispatch queue to execute the `listener` closure on. + open var listenerQueue: DispatchQueue = DispatchQueue.main + + /// A closure executed when the network reachability status changes. + open var listener: Listener? + + open var flags: SCNetworkReachabilityFlags? { + var flags = SCNetworkReachabilityFlags() + + if SCNetworkReachabilityGetFlags(reachability, &flags) { + return flags + } + + return nil + } + + private let reachability: SCNetworkReachability + open var previousFlags: SCNetworkReachabilityFlags + + // MARK: - Initialization + + /// Creates a `NetworkReachabilityManager` instance with the specified host. + /// + /// - parameter host: The host used to evaluate network reachability. + /// + /// - returns: The new `NetworkReachabilityManager` instance. + public convenience init?(host: String) { + guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else { return nil } + self.init(reachability: reachability) + } + + /// Creates a `NetworkReachabilityManager` instance that monitors the address 0.0.0.0. + /// + /// Reachability treats the 0.0.0.0 address as a special token that causes it to monitor the general routing + /// status of the device, both IPv4 and IPv6. + /// + /// - returns: The new `NetworkReachabilityManager` instance. + public convenience init?() { + var address = sockaddr_in() + address.sin_len = UInt8(MemoryLayout.size) + address.sin_family = sa_family_t(AF_INET) + + guard let reachability = withUnsafePointer(to: &address, { pointer in + return pointer.withMemoryRebound(to: sockaddr.self, capacity: MemoryLayout.size) { + return SCNetworkReachabilityCreateWithAddress(nil, $0) + } + }) else { return nil } + + self.init(reachability: reachability) + } + + private init(reachability: SCNetworkReachability) { + self.reachability = reachability + + // Set the previous flags to an unreserved value to represent unknown status + self.previousFlags = SCNetworkReachabilityFlags(rawValue: 1 << 30) + } + + deinit { + stopListening() + } + + // MARK: - Listening + + /// Starts listening for changes in network reachability status. + /// + /// - returns: `true` if listening was started successfully, `false` otherwise. + @discardableResult + open func startListening() -> Bool { + var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) + context.info = Unmanaged.passUnretained(self).toOpaque() + + let callbackEnabled = SCNetworkReachabilitySetCallback( + reachability, + { (_, flags, info) in + let reachability = Unmanaged.fromOpaque(info!).takeUnretainedValue() + reachability.notifyListener(flags) + }, + &context + ) + + let queueEnabled = SCNetworkReachabilitySetDispatchQueue(reachability, listenerQueue) + + listenerQueue.async { + self.previousFlags = SCNetworkReachabilityFlags(rawValue: 1 << 30) + + guard let flags = self.flags else { return } + + self.notifyListener(flags) + } + + return callbackEnabled && queueEnabled + } + + /// Stops listening for changes in network reachability status. + open func stopListening() { + SCNetworkReachabilitySetCallback(reachability, nil, nil) + SCNetworkReachabilitySetDispatchQueue(reachability, nil) + } + + // MARK: - Internal - Listener Notification + + func notifyListener(_ flags: SCNetworkReachabilityFlags) { + guard previousFlags != flags else { return } + previousFlags = flags + + listener?(networkReachabilityStatusForFlags(flags)) + } + + // MARK: - Internal - Network Reachability Status + + func networkReachabilityStatusForFlags(_ flags: SCNetworkReachabilityFlags) -> NetworkReachabilityStatus { + guard isNetworkReachable(with: flags) else { return .notReachable } + + var networkStatus: NetworkReachabilityStatus = .reachable(.ethernetOrWiFi) + + #if os(iOS) + if flags.contains(.isWWAN) { networkStatus = .reachable(.wwan) } + #endif + + return networkStatus + } + + func isNetworkReachable(with flags: SCNetworkReachabilityFlags) -> Bool { + let isReachable = flags.contains(.reachable) + let needsConnection = flags.contains(.connectionRequired) + let canConnectAutomatically = flags.contains(.connectionOnDemand) || flags.contains(.connectionOnTraffic) + let canConnectWithoutUserInteraction = canConnectAutomatically && !flags.contains(.interventionRequired) + + return isReachable && (!needsConnection || canConnectWithoutUserInteraction) + } +} + +// MARK: - + +extension NetworkReachabilityManager.NetworkReachabilityStatus: Equatable {} + +/// Returns whether the two network reachability status values are equal. +/// +/// - parameter lhs: The left-hand side value to compare. +/// - parameter rhs: The right-hand side value to compare. +/// +/// - returns: `true` if the two values are equal, `false` otherwise. +public func ==( + lhs: NetworkReachabilityManager.NetworkReachabilityStatus, + rhs: NetworkReachabilityManager.NetworkReachabilityStatus) + -> Bool +{ + switch (lhs, rhs) { + case (.unknown, .unknown): + return true + case (.notReachable, .notReachable): + return true + case let (.reachable(lhsConnectionType), .reachable(rhsConnectionType)): + return lhsConnectionType == rhsConnectionType + default: + return false + } +} + +#endif diff --git a/Pods/Alamofire/Source/Notifications.swift b/Pods/Alamofire/Source/Notifications.swift new file mode 100644 index 0000000..e1ac31b --- /dev/null +++ b/Pods/Alamofire/Source/Notifications.swift @@ -0,0 +1,55 @@ +// +// Notifications.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +extension Notification.Name { + /// Used as a namespace for all `URLSessionTask` related notifications. + public struct Task { + /// Posted when a `URLSessionTask` is resumed. The notification `object` contains the resumed `URLSessionTask`. + public static let DidResume = Notification.Name(rawValue: "org.alamofire.notification.name.task.didResume") + + /// Posted when a `URLSessionTask` is suspended. The notification `object` contains the suspended `URLSessionTask`. + public static let DidSuspend = Notification.Name(rawValue: "org.alamofire.notification.name.task.didSuspend") + + /// Posted when a `URLSessionTask` is cancelled. The notification `object` contains the cancelled `URLSessionTask`. + public static let DidCancel = Notification.Name(rawValue: "org.alamofire.notification.name.task.didCancel") + + /// Posted when a `URLSessionTask` is completed. The notification `object` contains the completed `URLSessionTask`. + public static let DidComplete = Notification.Name(rawValue: "org.alamofire.notification.name.task.didComplete") + } +} + +// MARK: - + +extension Notification { + /// Used as a namespace for all `Notification` user info dictionary keys. + public struct Key { + /// User info dictionary key representing the `URLSessionTask` associated with the notification. + public static let Task = "org.alamofire.notification.key.task" + + /// User info dictionary key representing the responseData associated with the notification. + public static let ResponseData = "org.alamofire.notification.key.responseData" + } +} diff --git a/Pods/Alamofire/Source/ParameterEncoding.swift b/Pods/Alamofire/Source/ParameterEncoding.swift new file mode 100644 index 0000000..6195809 --- /dev/null +++ b/Pods/Alamofire/Source/ParameterEncoding.swift @@ -0,0 +1,483 @@ +// +// ParameterEncoding.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// HTTP method definitions. +/// +/// See https://tools.ietf.org/html/rfc7231#section-4.3 +public enum HTTPMethod: String { + case options = "OPTIONS" + case get = "GET" + case head = "HEAD" + case post = "POST" + case put = "PUT" + case patch = "PATCH" + case delete = "DELETE" + case trace = "TRACE" + case connect = "CONNECT" +} + +// MARK: - + +/// A dictionary of parameters to apply to a `URLRequest`. +public typealias Parameters = [String: Any] + +/// A type used to define how a set of parameters are applied to a `URLRequest`. +public protocol ParameterEncoding { + /// Creates a URL request by encoding parameters and applying them onto an existing request. + /// + /// - parameter urlRequest: The request to have parameters applied. + /// - parameter parameters: The parameters to apply. + /// + /// - throws: An `AFError.parameterEncodingFailed` error if encoding fails. + /// + /// - returns: The encoded request. + func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest +} + +// MARK: - + +/// Creates a url-encoded query string to be set as or appended to any existing URL query string or set as the HTTP +/// body of the URL request. Whether the query string is set or appended to any existing URL query string or set as +/// the HTTP body depends on the destination of the encoding. +/// +/// The `Content-Type` HTTP header field of an encoded request with HTTP body is set to +/// `application/x-www-form-urlencoded; charset=utf-8`. +/// +/// There is no published specification for how to encode collection types. By default the convention of appending +/// `[]` to the key for array values (`foo[]=1&foo[]=2`), and appending the key surrounded by square brackets for +/// nested dictionary values (`foo[bar]=baz`) is used. Optionally, `ArrayEncoding` can be used to omit the +/// square brackets appended to array keys. +/// +/// `BoolEncoding` can be used to configure how boolean values are encoded. The default behavior is to encode +/// `true` as 1 and `false` as 0. +public struct URLEncoding: ParameterEncoding { + + // MARK: Helper Types + + /// Defines whether the url-encoded query string is applied to the existing query string or HTTP body of the + /// resulting URL request. + /// + /// - methodDependent: Applies encoded query string result to existing query string for `GET`, `HEAD` and `DELETE` + /// requests and sets as the HTTP body for requests with any other HTTP method. + /// - queryString: Sets or appends encoded query string result to existing query string. + /// - httpBody: Sets encoded query string result as the HTTP body of the URL request. + public enum Destination { + case methodDependent, queryString, httpBody + } + + /// Configures how `Array` parameters are encoded. + /// + /// - brackets: An empty set of square brackets is appended to the key for every value. + /// This is the default behavior. + /// - noBrackets: No brackets are appended. The key is encoded as is. + public enum ArrayEncoding { + case brackets, noBrackets + + func encode(key: String) -> String { + switch self { + case .brackets: + return "\(key)[]" + case .noBrackets: + return key + } + } + } + + /// Configures how `Bool` parameters are encoded. + /// + /// - numeric: Encode `true` as `1` and `false` as `0`. This is the default behavior. + /// - literal: Encode `true` and `false` as string literals. + public enum BoolEncoding { + case numeric, literal + + func encode(value: Bool) -> String { + switch self { + case .numeric: + return value ? "1" : "0" + case .literal: + return value ? "true" : "false" + } + } + } + + // MARK: Properties + + /// Returns a default `URLEncoding` instance. + public static var `default`: URLEncoding { return URLEncoding() } + + /// Returns a `URLEncoding` instance with a `.methodDependent` destination. + public static var methodDependent: URLEncoding { return URLEncoding() } + + /// Returns a `URLEncoding` instance with a `.queryString` destination. + public static var queryString: URLEncoding { return URLEncoding(destination: .queryString) } + + /// Returns a `URLEncoding` instance with an `.httpBody` destination. + public static var httpBody: URLEncoding { return URLEncoding(destination: .httpBody) } + + /// The destination defining where the encoded query string is to be applied to the URL request. + public let destination: Destination + + /// The encoding to use for `Array` parameters. + public let arrayEncoding: ArrayEncoding + + /// The encoding to use for `Bool` parameters. + public let boolEncoding: BoolEncoding + + // MARK: Initialization + + /// Creates a `URLEncoding` instance using the specified destination. + /// + /// - parameter destination: The destination defining where the encoded query string is to be applied. + /// - parameter arrayEncoding: The encoding to use for `Array` parameters. + /// - parameter boolEncoding: The encoding to use for `Bool` parameters. + /// + /// - returns: The new `URLEncoding` instance. + public init(destination: Destination = .methodDependent, arrayEncoding: ArrayEncoding = .brackets, boolEncoding: BoolEncoding = .numeric) { + self.destination = destination + self.arrayEncoding = arrayEncoding + self.boolEncoding = boolEncoding + } + + // MARK: Encoding + + /// Creates a URL request by encoding parameters and applying them onto an existing request. + /// + /// - parameter urlRequest: The request to have parameters applied. + /// - parameter parameters: The parameters to apply. + /// + /// - throws: An `Error` if the encoding process encounters an error. + /// + /// - returns: The encoded request. + public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { + var urlRequest = try urlRequest.asURLRequest() + + guard let parameters = parameters else { return urlRequest } + + if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) { + guard let url = urlRequest.url else { + throw AFError.parameterEncodingFailed(reason: .missingURL) + } + + if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty { + let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters) + urlComponents.percentEncodedQuery = percentEncodedQuery + urlRequest.url = urlComponents.url + } + } else { + if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { + urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type") + } + + urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false) + } + + return urlRequest + } + + /// Creates percent-escaped, URL encoded query string components from the given key-value pair using recursion. + /// + /// - parameter key: The key of the query component. + /// - parameter value: The value of the query component. + /// + /// - returns: The percent-escaped, URL encoded query string components. + public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] { + var components: [(String, String)] = [] + + if let dictionary = value as? [String: Any] { + for (nestedKey, value) in dictionary { + components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value) + } + } else if let array = value as? [Any] { + for value in array { + components += queryComponents(fromKey: arrayEncoding.encode(key: key), value: value) + } + } else if let value = value as? NSNumber { + if value.isBool { + components.append((escape(key), escape(boolEncoding.encode(value: value.boolValue)))) + } else { + components.append((escape(key), escape("\(value)"))) + } + } else if let bool = value as? Bool { + components.append((escape(key), escape(boolEncoding.encode(value: bool)))) + } else { + components.append((escape(key), escape("\(value)"))) + } + + return components + } + + /// Returns a percent-escaped string following RFC 3986 for a query string key or value. + /// + /// RFC 3986 states that the following characters are "reserved" characters. + /// + /// - General Delimiters: ":", "#", "[", "]", "@", "?", "/" + /// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=" + /// + /// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow + /// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/" + /// should be percent-escaped in the query string. + /// + /// - parameter string: The string to be percent-escaped. + /// + /// - returns: The percent-escaped string. + public func escape(_ string: String) -> String { + let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4 + let subDelimitersToEncode = "!$&'()*+,;=" + + var allowedCharacterSet = CharacterSet.urlQueryAllowed + allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)") + + var escaped = "" + + //========================================================================================================== + // + // Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few + // hundred Chinese characters causes various malloc error crashes. To avoid this issue until iOS 8 is no + // longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead. For more + // info, please refer to: + // + // - https://github.com/Alamofire/Alamofire/issues/206 + // + //========================================================================================================== + + if #available(iOS 8.3, *) { + escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string + } else { + let batchSize = 50 + var index = string.startIndex + + while index != string.endIndex { + let startIndex = index + let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex + let range = startIndex.. String { + var components: [(String, String)] = [] + + for key in parameters.keys.sorted(by: <) { + let value = parameters[key]! + components += queryComponents(fromKey: key, value: value) + } + return components.map { "\($0)=\($1)" }.joined(separator: "&") + } + + private func encodesParametersInURL(with method: HTTPMethod) -> Bool { + switch destination { + case .queryString: + return true + case .httpBody: + return false + default: + break + } + + switch method { + case .get, .head, .delete: + return true + default: + return false + } + } +} + +// MARK: - + +/// Uses `JSONSerialization` to create a JSON representation of the parameters object, which is set as the body of the +/// request. The `Content-Type` HTTP header field of an encoded request is set to `application/json`. +public struct JSONEncoding: ParameterEncoding { + + // MARK: Properties + + /// Returns a `JSONEncoding` instance with default writing options. + public static var `default`: JSONEncoding { return JSONEncoding() } + + /// Returns a `JSONEncoding` instance with `.prettyPrinted` writing options. + public static var prettyPrinted: JSONEncoding { return JSONEncoding(options: .prettyPrinted) } + + /// The options for writing the parameters as JSON data. + public let options: JSONSerialization.WritingOptions + + // MARK: Initialization + + /// Creates a `JSONEncoding` instance using the specified options. + /// + /// - parameter options: The options for writing the parameters as JSON data. + /// + /// - returns: The new `JSONEncoding` instance. + public init(options: JSONSerialization.WritingOptions = []) { + self.options = options + } + + // MARK: Encoding + + /// Creates a URL request by encoding parameters and applying them onto an existing request. + /// + /// - parameter urlRequest: The request to have parameters applied. + /// - parameter parameters: The parameters to apply. + /// + /// - throws: An `Error` if the encoding process encounters an error. + /// + /// - returns: The encoded request. + public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { + var urlRequest = try urlRequest.asURLRequest() + + guard let parameters = parameters else { return urlRequest } + + do { + let data = try JSONSerialization.data(withJSONObject: parameters, options: options) + + if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { + urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") + } + + urlRequest.httpBody = data + } catch { + throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) + } + + return urlRequest + } + + /// Creates a URL request by encoding the JSON object and setting the resulting data on the HTTP body. + /// + /// - parameter urlRequest: The request to apply the JSON object to. + /// - parameter jsonObject: The JSON object to apply to the request. + /// + /// - throws: An `Error` if the encoding process encounters an error. + /// + /// - returns: The encoded request. + public func encode(_ urlRequest: URLRequestConvertible, withJSONObject jsonObject: Any? = nil) throws -> URLRequest { + var urlRequest = try urlRequest.asURLRequest() + + guard let jsonObject = jsonObject else { return urlRequest } + + do { + let data = try JSONSerialization.data(withJSONObject: jsonObject, options: options) + + if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { + urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") + } + + urlRequest.httpBody = data + } catch { + throw AFError.parameterEncodingFailed(reason: .jsonEncodingFailed(error: error)) + } + + return urlRequest + } +} + +// MARK: - + +/// Uses `PropertyListSerialization` to create a plist representation of the parameters object, according to the +/// associated format and write options values, which is set as the body of the request. The `Content-Type` HTTP header +/// field of an encoded request is set to `application/x-plist`. +public struct PropertyListEncoding: ParameterEncoding { + + // MARK: Properties + + /// Returns a default `PropertyListEncoding` instance. + public static var `default`: PropertyListEncoding { return PropertyListEncoding() } + + /// Returns a `PropertyListEncoding` instance with xml formatting and default writing options. + public static var xml: PropertyListEncoding { return PropertyListEncoding(format: .xml) } + + /// Returns a `PropertyListEncoding` instance with binary formatting and default writing options. + public static var binary: PropertyListEncoding { return PropertyListEncoding(format: .binary) } + + /// The property list serialization format. + public let format: PropertyListSerialization.PropertyListFormat + + /// The options for writing the parameters as plist data. + public let options: PropertyListSerialization.WriteOptions + + // MARK: Initialization + + /// Creates a `PropertyListEncoding` instance using the specified format and options. + /// + /// - parameter format: The property list serialization format. + /// - parameter options: The options for writing the parameters as plist data. + /// + /// - returns: The new `PropertyListEncoding` instance. + public init( + format: PropertyListSerialization.PropertyListFormat = .xml, + options: PropertyListSerialization.WriteOptions = 0) + { + self.format = format + self.options = options + } + + // MARK: Encoding + + /// Creates a URL request by encoding parameters and applying them onto an existing request. + /// + /// - parameter urlRequest: The request to have parameters applied. + /// - parameter parameters: The parameters to apply. + /// + /// - throws: An `Error` if the encoding process encounters an error. + /// + /// - returns: The encoded request. + public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { + var urlRequest = try urlRequest.asURLRequest() + + guard let parameters = parameters else { return urlRequest } + + do { + let data = try PropertyListSerialization.data( + fromPropertyList: parameters, + format: format, + options: options + ) + + if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil { + urlRequest.setValue("application/x-plist", forHTTPHeaderField: "Content-Type") + } + + urlRequest.httpBody = data + } catch { + throw AFError.parameterEncodingFailed(reason: .propertyListEncodingFailed(error: error)) + } + + return urlRequest + } +} + +// MARK: - + +extension NSNumber { + fileprivate var isBool: Bool { return CFBooleanGetTypeID() == CFGetTypeID(self) } +} diff --git a/Pods/Alamofire/Source/Request.swift b/Pods/Alamofire/Source/Request.swift new file mode 100644 index 0000000..2be2ce0 --- /dev/null +++ b/Pods/Alamofire/Source/Request.swift @@ -0,0 +1,660 @@ +// +// Request.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// A type that can inspect and optionally adapt a `URLRequest` in some manner if necessary. +public protocol RequestAdapter { + /// Inspects and adapts the specified `URLRequest` in some manner if necessary and returns the result. + /// + /// - parameter urlRequest: The URL request to adapt. + /// + /// - throws: An `Error` if the adaptation encounters an error. + /// + /// - returns: The adapted `URLRequest`. + func adapt(_ urlRequest: URLRequest) throws -> URLRequest +} + +// MARK: - + +/// A closure executed when the `RequestRetrier` determines whether a `Request` should be retried or not. +public typealias RequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval) -> Void + +/// A type that determines whether a request should be retried after being executed by the specified session manager +/// and encountering an error. +public protocol RequestRetrier { + /// Determines whether the `Request` should be retried by calling the `completion` closure. + /// + /// This operation is fully asynchronous. Any amount of time can be taken to determine whether the request needs + /// to be retried. The one requirement is that the completion closure is called to ensure the request is properly + /// cleaned up after. + /// + /// - parameter manager: The session manager the request was executed on. + /// - parameter request: The request that failed due to the encountered error. + /// - parameter error: The error encountered when executing the request. + /// - parameter completion: The completion closure to be executed when retry decision has been determined. + func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) +} + +// MARK: - + +protocol TaskConvertible { + func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask +} + +/// A dictionary of headers to apply to a `URLRequest`. +public typealias HTTPHeaders = [String: String] + +// MARK: - + +/// Responsible for sending a request and receiving the response and associated data from the server, as well as +/// managing its underlying `URLSessionTask`. +open class Request { + + // MARK: Helper Types + + /// A closure executed when monitoring upload or download progress of a request. + public typealias ProgressHandler = (Progress) -> Void + + enum RequestTask { + case data(TaskConvertible?, URLSessionTask?) + case download(TaskConvertible?, URLSessionTask?) + case upload(TaskConvertible?, URLSessionTask?) + case stream(TaskConvertible?, URLSessionTask?) + } + + // MARK: Properties + + /// The delegate for the underlying task. + open internal(set) var delegate: TaskDelegate { + get { + taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() } + return taskDelegate + } + set { + taskDelegateLock.lock() ; defer { taskDelegateLock.unlock() } + taskDelegate = newValue + } + } + + /// The underlying task. + open var task: URLSessionTask? { return delegate.task } + + /// The session belonging to the underlying task. + public let session: URLSession + + /// The request sent or to be sent to the server. + open var request: URLRequest? { return task?.originalRequest } + + /// The response received from the server, if any. + open var response: HTTPURLResponse? { return task?.response as? HTTPURLResponse } + + /// The number of times the request has been retried. + open internal(set) var retryCount: UInt = 0 + + let originalTask: TaskConvertible? + + var startTime: CFAbsoluteTime? + var endTime: CFAbsoluteTime? + + var validations: [() -> Void] = [] + + private var taskDelegate: TaskDelegate + private var taskDelegateLock = NSLock() + + // MARK: Lifecycle + + init(session: URLSession, requestTask: RequestTask, error: Error? = nil) { + self.session = session + + switch requestTask { + case .data(let originalTask, let task): + taskDelegate = DataTaskDelegate(task: task) + self.originalTask = originalTask + case .download(let originalTask, let task): + taskDelegate = DownloadTaskDelegate(task: task) + self.originalTask = originalTask + case .upload(let originalTask, let task): + taskDelegate = UploadTaskDelegate(task: task) + self.originalTask = originalTask + case .stream(let originalTask, let task): + taskDelegate = TaskDelegate(task: task) + self.originalTask = originalTask + } + + delegate.error = error + delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() } + } + + // MARK: Authentication + + /// Associates an HTTP Basic credential with the request. + /// + /// - parameter user: The user. + /// - parameter password: The password. + /// - parameter persistence: The URL credential persistence. `.ForSession` by default. + /// + /// - returns: The request. + @discardableResult + open func authenticate( + user: String, + password: String, + persistence: URLCredential.Persistence = .forSession) + -> Self + { + let credential = URLCredential(user: user, password: password, persistence: persistence) + return authenticate(usingCredential: credential) + } + + /// Associates a specified credential with the request. + /// + /// - parameter credential: The credential. + /// + /// - returns: The request. + @discardableResult + open func authenticate(usingCredential credential: URLCredential) -> Self { + delegate.credential = credential + return self + } + + /// Returns a base64 encoded basic authentication credential as an authorization header tuple. + /// + /// - parameter user: The user. + /// - parameter password: The password. + /// + /// - returns: A tuple with Authorization header and credential value if encoding succeeds, `nil` otherwise. + open class func authorizationHeader(user: String, password: String) -> (key: String, value: String)? { + guard let data = "\(user):\(password)".data(using: .utf8) else { return nil } + + let credential = data.base64EncodedString(options: []) + + return (key: "Authorization", value: "Basic \(credential)") + } + + // MARK: State + + /// Resumes the request. + open func resume() { + guard let task = task else { delegate.queue.isSuspended = false ; return } + + if startTime == nil { startTime = CFAbsoluteTimeGetCurrent() } + + task.resume() + + NotificationCenter.default.post( + name: Notification.Name.Task.DidResume, + object: self, + userInfo: [Notification.Key.Task: task] + ) + } + + /// Suspends the request. + open func suspend() { + guard let task = task else { return } + + task.suspend() + + NotificationCenter.default.post( + name: Notification.Name.Task.DidSuspend, + object: self, + userInfo: [Notification.Key.Task: task] + ) + } + + /// Cancels the request. + open func cancel() { + guard let task = task else { return } + + task.cancel() + + NotificationCenter.default.post( + name: Notification.Name.Task.DidCancel, + object: self, + userInfo: [Notification.Key.Task: task] + ) + } +} + +// MARK: - CustomStringConvertible + +extension Request: CustomStringConvertible { + /// The textual representation used when written to an output stream, which includes the HTTP method and URL, as + /// well as the response status code if a response has been received. + open var description: String { + var components: [String] = [] + + if let HTTPMethod = request?.httpMethod { + components.append(HTTPMethod) + } + + if let urlString = request?.url?.absoluteString { + components.append(urlString) + } + + if let response = response { + components.append("(\(response.statusCode))") + } + + return components.joined(separator: " ") + } +} + +// MARK: - CustomDebugStringConvertible + +extension Request: CustomDebugStringConvertible { + /// The textual representation used when written to an output stream, in the form of a cURL command. + open var debugDescription: String { + return cURLRepresentation() + } + + func cURLRepresentation() -> String { + var components = ["$ curl -v"] + + guard let request = self.request, + let url = request.url, + let host = url.host + else { + return "$ curl command could not be created" + } + + if let httpMethod = request.httpMethod, httpMethod != "GET" { + components.append("-X \(httpMethod)") + } + + if let credentialStorage = self.session.configuration.urlCredentialStorage { + let protectionSpace = URLProtectionSpace( + host: host, + port: url.port ?? 0, + protocol: url.scheme, + realm: host, + authenticationMethod: NSURLAuthenticationMethodHTTPBasic + ) + + if let credentials = credentialStorage.credentials(for: protectionSpace)?.values { + for credential in credentials { + guard let user = credential.user, let password = credential.password else { continue } + components.append("-u \(user):\(password)") + } + } else { + if let credential = delegate.credential, let user = credential.user, let password = credential.password { + components.append("-u \(user):\(password)") + } + } + } + + if session.configuration.httpShouldSetCookies { + if + let cookieStorage = session.configuration.httpCookieStorage, + let cookies = cookieStorage.cookies(for: url), !cookies.isEmpty + { + let string = cookies.reduce("") { $0 + "\($1.name)=\($1.value);" } + + #if swift(>=3.2) + components.append("-b \"\(string[.. URLSessionTask { + do { + let urlRequest = try self.urlRequest.adapt(using: adapter) + return queue.sync { session.dataTask(with: urlRequest) } + } catch { + throw AdaptError(error: error) + } + } + } + + // MARK: Properties + + /// The request sent or to be sent to the server. + open override var request: URLRequest? { + if let request = super.request { return request } + if let requestable = originalTask as? Requestable { return requestable.urlRequest } + + return nil + } + + /// The progress of fetching the response data from the server for the request. + open var progress: Progress { return dataDelegate.progress } + + var dataDelegate: DataTaskDelegate { return delegate as! DataTaskDelegate } + + // MARK: Stream + + /// Sets a closure to be called periodically during the lifecycle of the request as data is read from the server. + /// + /// This closure returns the bytes most recently received from the server, not including data from previous calls. + /// If this closure is set, data will only be available within this closure, and will not be saved elsewhere. It is + /// also important to note that the server data in any `Response` object will be `nil`. + /// + /// - parameter closure: The code to be executed periodically during the lifecycle of the request. + /// + /// - returns: The request. + @discardableResult + open func stream(closure: ((Data) -> Void)? = nil) -> Self { + dataDelegate.dataStream = closure + return self + } + + // MARK: Progress + + /// Sets a closure to be called periodically during the lifecycle of the `Request` as data is read from the server. + /// + /// - parameter queue: The dispatch queue to execute the closure on. + /// - parameter closure: The code to be executed periodically as data is read from the server. + /// + /// - returns: The request. + @discardableResult + open func downloadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self { + dataDelegate.progressHandler = (closure, queue) + return self + } +} + +// MARK: - + +/// Specific type of `Request` that manages an underlying `URLSessionDownloadTask`. +open class DownloadRequest: Request { + + // MARK: Helper Types + + /// A collection of options to be executed prior to moving a downloaded file from the temporary URL to the + /// destination URL. + public struct DownloadOptions: OptionSet { + /// Returns the raw bitmask value of the option and satisfies the `RawRepresentable` protocol. + public let rawValue: UInt + + /// A `DownloadOptions` flag that creates intermediate directories for the destination URL if specified. + public static let createIntermediateDirectories = DownloadOptions(rawValue: 1 << 0) + + /// A `DownloadOptions` flag that removes a previous file from the destination URL if specified. + public static let removePreviousFile = DownloadOptions(rawValue: 1 << 1) + + /// Creates a `DownloadFileDestinationOptions` instance with the specified raw value. + /// + /// - parameter rawValue: The raw bitmask value for the option. + /// + /// - returns: A new log level instance. + public init(rawValue: UInt) { + self.rawValue = rawValue + } + } + + /// A closure executed once a download request has successfully completed in order to determine where to move the + /// temporary file written to during the download process. The closure takes two arguments: the temporary file URL + /// and the URL response, and returns a two arguments: the file URL where the temporary file should be moved and + /// the options defining how the file should be moved. + public typealias DownloadFileDestination = ( + _ temporaryURL: URL, + _ response: HTTPURLResponse) + -> (destinationURL: URL, options: DownloadOptions) + + enum Downloadable: TaskConvertible { + case request(URLRequest) + case resumeData(Data) + + func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask { + do { + let task: URLSessionTask + + switch self { + case let .request(urlRequest): + let urlRequest = try urlRequest.adapt(using: adapter) + task = queue.sync { session.downloadTask(with: urlRequest) } + case let .resumeData(resumeData): + task = queue.sync { session.downloadTask(withResumeData: resumeData) } + } + + return task + } catch { + throw AdaptError(error: error) + } + } + } + + // MARK: Properties + + /// The request sent or to be sent to the server. + open override var request: URLRequest? { + if let request = super.request { return request } + + if let downloadable = originalTask as? Downloadable, case let .request(urlRequest) = downloadable { + return urlRequest + } + + return nil + } + + /// The resume data of the underlying download task if available after a failure. + open var resumeData: Data? { return downloadDelegate.resumeData } + + /// The progress of downloading the response data from the server for the request. + open var progress: Progress { return downloadDelegate.progress } + + var downloadDelegate: DownloadTaskDelegate { return delegate as! DownloadTaskDelegate } + + // MARK: State + + /// Cancels the request. + override open func cancel() { + cancel(createResumeData: true) + } + + /// Cancels the request. + /// + /// - parameter createResumeData: Determines whether resume data is created via the underlying download task or not. + open func cancel(createResumeData: Bool) { + if createResumeData { + downloadDelegate.downloadTask.cancel { self.downloadDelegate.resumeData = $0 } + } else { + downloadDelegate.downloadTask.cancel() + } + + NotificationCenter.default.post( + name: Notification.Name.Task.DidCancel, + object: self, + userInfo: [Notification.Key.Task: task as Any] + ) + } + + // MARK: Progress + + /// Sets a closure to be called periodically during the lifecycle of the `Request` as data is read from the server. + /// + /// - parameter queue: The dispatch queue to execute the closure on. + /// - parameter closure: The code to be executed periodically as data is read from the server. + /// + /// - returns: The request. + @discardableResult + open func downloadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self { + downloadDelegate.progressHandler = (closure, queue) + return self + } + + // MARK: Destination + + /// Creates a download file destination closure which uses the default file manager to move the temporary file to a + /// file URL in the first available directory with the specified search path directory and search path domain mask. + /// + /// - parameter directory: The search path directory. `.DocumentDirectory` by default. + /// - parameter domain: The search path domain mask. `.UserDomainMask` by default. + /// + /// - returns: A download file destination closure. + open class func suggestedDownloadDestination( + for directory: FileManager.SearchPathDirectory = .documentDirectory, + in domain: FileManager.SearchPathDomainMask = .userDomainMask) + -> DownloadFileDestination + { + return { temporaryURL, response in + let directoryURLs = FileManager.default.urls(for: directory, in: domain) + + if !directoryURLs.isEmpty { + return (directoryURLs[0].appendingPathComponent(response.suggestedFilename!), []) + } + + return (temporaryURL, []) + } + } +} + +// MARK: - + +/// Specific type of `Request` that manages an underlying `URLSessionUploadTask`. +open class UploadRequest: DataRequest { + + // MARK: Helper Types + + enum Uploadable: TaskConvertible { + case data(Data, URLRequest) + case file(URL, URLRequest) + case stream(InputStream, URLRequest) + + func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask { + do { + let task: URLSessionTask + + switch self { + case let .data(data, urlRequest): + let urlRequest = try urlRequest.adapt(using: adapter) + task = queue.sync { session.uploadTask(with: urlRequest, from: data) } + case let .file(url, urlRequest): + let urlRequest = try urlRequest.adapt(using: adapter) + task = queue.sync { session.uploadTask(with: urlRequest, fromFile: url) } + case let .stream(_, urlRequest): + let urlRequest = try urlRequest.adapt(using: adapter) + task = queue.sync { session.uploadTask(withStreamedRequest: urlRequest) } + } + + return task + } catch { + throw AdaptError(error: error) + } + } + } + + // MARK: Properties + + /// The request sent or to be sent to the server. + open override var request: URLRequest? { + if let request = super.request { return request } + + guard let uploadable = originalTask as? Uploadable else { return nil } + + switch uploadable { + case .data(_, let urlRequest), .file(_, let urlRequest), .stream(_, let urlRequest): + return urlRequest + } + } + + /// The progress of uploading the payload to the server for the upload request. + open var uploadProgress: Progress { return uploadDelegate.uploadProgress } + + var uploadDelegate: UploadTaskDelegate { return delegate as! UploadTaskDelegate } + + // MARK: Upload Progress + + /// Sets a closure to be called periodically during the lifecycle of the `UploadRequest` as data is sent to + /// the server. + /// + /// After the data is sent to the server, the `progress(queue:closure:)` APIs can be used to monitor the progress + /// of data being read from the server. + /// + /// - parameter queue: The dispatch queue to execute the closure on. + /// - parameter closure: The code to be executed periodically as data is sent to the server. + /// + /// - returns: The request. + @discardableResult + open func uploadProgress(queue: DispatchQueue = DispatchQueue.main, closure: @escaping ProgressHandler) -> Self { + uploadDelegate.uploadProgressHandler = (closure, queue) + return self + } +} + +// MARK: - + +#if !os(watchOS) + +/// Specific type of `Request` that manages an underlying `URLSessionStreamTask`. +@available(iOS 9.0, macOS 10.11, tvOS 9.0, *) +open class StreamRequest: Request { + enum Streamable: TaskConvertible { + case stream(hostName: String, port: Int) + case netService(NetService) + + func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask { + let task: URLSessionTask + + switch self { + case let .stream(hostName, port): + task = queue.sync { session.streamTask(withHostName: hostName, port: port) } + case let .netService(netService): + task = queue.sync { session.streamTask(with: netService) } + } + + return task + } + } +} + +#endif diff --git a/Pods/Alamofire/Source/Response.swift b/Pods/Alamofire/Source/Response.swift new file mode 100644 index 0000000..747a471 --- /dev/null +++ b/Pods/Alamofire/Source/Response.swift @@ -0,0 +1,567 @@ +// +// Response.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// Used to store all data associated with an non-serialized response of a data or upload request. +public struct DefaultDataResponse { + /// The URL request sent to the server. + public let request: URLRequest? + + /// The server's response to the URL request. + public let response: HTTPURLResponse? + + /// The data returned by the server. + public let data: Data? + + /// The error encountered while executing or validating the request. + public let error: Error? + + /// The timeline of the complete lifecycle of the request. + public let timeline: Timeline + + var _metrics: AnyObject? + + /// Creates a `DefaultDataResponse` instance from the specified parameters. + /// + /// - Parameters: + /// - request: The URL request sent to the server. + /// - response: The server's response to the URL request. + /// - data: The data returned by the server. + /// - error: The error encountered while executing or validating the request. + /// - timeline: The timeline of the complete lifecycle of the request. `Timeline()` by default. + /// - metrics: The task metrics containing the request / response statistics. `nil` by default. + public init( + request: URLRequest?, + response: HTTPURLResponse?, + data: Data?, + error: Error?, + timeline: Timeline = Timeline(), + metrics: AnyObject? = nil) + { + self.request = request + self.response = response + self.data = data + self.error = error + self.timeline = timeline + } +} + +// MARK: - + +/// Used to store all data associated with a serialized response of a data or upload request. +public struct DataResponse { + /// The URL request sent to the server. + public let request: URLRequest? + + /// The server's response to the URL request. + public let response: HTTPURLResponse? + + /// The data returned by the server. + public let data: Data? + + /// The result of response serialization. + public let result: Result + + /// The timeline of the complete lifecycle of the request. + public let timeline: Timeline + + /// Returns the associated value of the result if it is a success, `nil` otherwise. + public var value: Value? { return result.value } + + /// Returns the associated error value if the result if it is a failure, `nil` otherwise. + public var error: Error? { return result.error } + + var _metrics: AnyObject? + + /// Creates a `DataResponse` instance with the specified parameters derived from response serialization. + /// + /// - parameter request: The URL request sent to the server. + /// - parameter response: The server's response to the URL request. + /// - parameter data: The data returned by the server. + /// - parameter result: The result of response serialization. + /// - parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`. + /// + /// - returns: The new `DataResponse` instance. + public init( + request: URLRequest?, + response: HTTPURLResponse?, + data: Data?, + result: Result, + timeline: Timeline = Timeline()) + { + self.request = request + self.response = response + self.data = data + self.result = result + self.timeline = timeline + } +} + +// MARK: - + +extension DataResponse: CustomStringConvertible, CustomDebugStringConvertible { + /// The textual representation used when written to an output stream, which includes whether the result was a + /// success or failure. + public var description: String { + return result.debugDescription + } + + /// The debug textual representation used when written to an output stream, which includes the URL request, the URL + /// response, the server data, the response serialization result and the timeline. + public var debugDescription: String { + var output: [String] = [] + + output.append(request != nil ? "[Request]: \(request!.httpMethod ?? "GET") \(request!)" : "[Request]: nil") + output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil") + output.append("[Data]: \(data?.count ?? 0) bytes") + output.append("[Result]: \(result.debugDescription)") + output.append("[Timeline]: \(timeline.debugDescription)") + + return output.joined(separator: "\n") + } +} + +// MARK: - + +extension DataResponse { + /// Evaluates the specified closure when the result of this `DataResponse` is a success, passing the unwrapped + /// result value as a parameter. + /// + /// Use the `map` method with a closure that does not throw. For example: + /// + /// let possibleData: DataResponse = ... + /// let possibleInt = possibleData.map { $0.count } + /// + /// - parameter transform: A closure that takes the success value of the instance's result. + /// + /// - returns: A `DataResponse` whose result wraps the value returned by the given closure. If this instance's + /// result is a failure, returns a response wrapping the same failure. + public func map(_ transform: (Value) -> T) -> DataResponse { + var response = DataResponse( + request: request, + response: self.response, + data: data, + result: result.map(transform), + timeline: timeline + ) + + response._metrics = _metrics + + return response + } + + /// Evaluates the given closure when the result of this `DataResponse` is a success, passing the unwrapped result + /// value as a parameter. + /// + /// Use the `flatMap` method with a closure that may throw an error. For example: + /// + /// let possibleData: DataResponse = ... + /// let possibleObject = possibleData.flatMap { + /// try JSONSerialization.jsonObject(with: $0) + /// } + /// + /// - parameter transform: A closure that takes the success value of the instance's result. + /// + /// - returns: A success or failure `DataResponse` depending on the result of the given closure. If this instance's + /// result is a failure, returns the same failure. + public func flatMap(_ transform: (Value) throws -> T) -> DataResponse { + var response = DataResponse( + request: request, + response: self.response, + data: data, + result: result.flatMap(transform), + timeline: timeline + ) + + response._metrics = _metrics + + return response + } + + /// Evaluates the specified closure when the `DataResponse` is a failure, passing the unwrapped error as a parameter. + /// + /// Use the `mapError` function with a closure that does not throw. For example: + /// + /// let possibleData: DataResponse = ... + /// let withMyError = possibleData.mapError { MyError.error($0) } + /// + /// - Parameter transform: A closure that takes the error of the instance. + /// - Returns: A `DataResponse` instance containing the result of the transform. + public func mapError(_ transform: (Error) -> E) -> DataResponse { + var response = DataResponse( + request: request, + response: self.response, + data: data, + result: result.mapError(transform), + timeline: timeline + ) + + response._metrics = _metrics + + return response + } + + /// Evaluates the specified closure when the `DataResponse` is a failure, passing the unwrapped error as a parameter. + /// + /// Use the `flatMapError` function with a closure that may throw an error. For example: + /// + /// let possibleData: DataResponse = ... + /// let possibleObject = possibleData.flatMapError { + /// try someFailableFunction(taking: $0) + /// } + /// + /// - Parameter transform: A throwing closure that takes the error of the instance. + /// + /// - Returns: A `DataResponse` instance containing the result of the transform. + public func flatMapError(_ transform: (Error) throws -> E) -> DataResponse { + var response = DataResponse( + request: request, + response: self.response, + data: data, + result: result.flatMapError(transform), + timeline: timeline + ) + + response._metrics = _metrics + + return response + } +} + +// MARK: - + +/// Used to store all data associated with an non-serialized response of a download request. +public struct DefaultDownloadResponse { + /// The URL request sent to the server. + public let request: URLRequest? + + /// The server's response to the URL request. + public let response: HTTPURLResponse? + + /// The temporary destination URL of the data returned from the server. + public let temporaryURL: URL? + + /// The final destination URL of the data returned from the server if it was moved. + public let destinationURL: URL? + + /// The resume data generated if the request was cancelled. + public let resumeData: Data? + + /// The error encountered while executing or validating the request. + public let error: Error? + + /// The timeline of the complete lifecycle of the request. + public let timeline: Timeline + + var _metrics: AnyObject? + + /// Creates a `DefaultDownloadResponse` instance from the specified parameters. + /// + /// - Parameters: + /// - request: The URL request sent to the server. + /// - response: The server's response to the URL request. + /// - temporaryURL: The temporary destination URL of the data returned from the server. + /// - destinationURL: The final destination URL of the data returned from the server if it was moved. + /// - resumeData: The resume data generated if the request was cancelled. + /// - error: The error encountered while executing or validating the request. + /// - timeline: The timeline of the complete lifecycle of the request. `Timeline()` by default. + /// - metrics: The task metrics containing the request / response statistics. `nil` by default. + public init( + request: URLRequest?, + response: HTTPURLResponse?, + temporaryURL: URL?, + destinationURL: URL?, + resumeData: Data?, + error: Error?, + timeline: Timeline = Timeline(), + metrics: AnyObject? = nil) + { + self.request = request + self.response = response + self.temporaryURL = temporaryURL + self.destinationURL = destinationURL + self.resumeData = resumeData + self.error = error + self.timeline = timeline + } +} + +// MARK: - + +/// Used to store all data associated with a serialized response of a download request. +public struct DownloadResponse { + /// The URL request sent to the server. + public let request: URLRequest? + + /// The server's response to the URL request. + public let response: HTTPURLResponse? + + /// The temporary destination URL of the data returned from the server. + public let temporaryURL: URL? + + /// The final destination URL of the data returned from the server if it was moved. + public let destinationURL: URL? + + /// The resume data generated if the request was cancelled. + public let resumeData: Data? + + /// The result of response serialization. + public let result: Result + + /// The timeline of the complete lifecycle of the request. + public let timeline: Timeline + + /// Returns the associated value of the result if it is a success, `nil` otherwise. + public var value: Value? { return result.value } + + /// Returns the associated error value if the result if it is a failure, `nil` otherwise. + public var error: Error? { return result.error } + + var _metrics: AnyObject? + + /// Creates a `DownloadResponse` instance with the specified parameters derived from response serialization. + /// + /// - parameter request: The URL request sent to the server. + /// - parameter response: The server's response to the URL request. + /// - parameter temporaryURL: The temporary destination URL of the data returned from the server. + /// - parameter destinationURL: The final destination URL of the data returned from the server if it was moved. + /// - parameter resumeData: The resume data generated if the request was cancelled. + /// - parameter result: The result of response serialization. + /// - parameter timeline: The timeline of the complete lifecycle of the `Request`. Defaults to `Timeline()`. + /// + /// - returns: The new `DownloadResponse` instance. + public init( + request: URLRequest?, + response: HTTPURLResponse?, + temporaryURL: URL?, + destinationURL: URL?, + resumeData: Data?, + result: Result, + timeline: Timeline = Timeline()) + { + self.request = request + self.response = response + self.temporaryURL = temporaryURL + self.destinationURL = destinationURL + self.resumeData = resumeData + self.result = result + self.timeline = timeline + } +} + +// MARK: - + +extension DownloadResponse: CustomStringConvertible, CustomDebugStringConvertible { + /// The textual representation used when written to an output stream, which includes whether the result was a + /// success or failure. + public var description: String { + return result.debugDescription + } + + /// The debug textual representation used when written to an output stream, which includes the URL request, the URL + /// response, the temporary and destination URLs, the resume data, the response serialization result and the + /// timeline. + public var debugDescription: String { + var output: [String] = [] + + output.append(request != nil ? "[Request]: \(request!.httpMethod ?? "GET") \(request!)" : "[Request]: nil") + output.append(response != nil ? "[Response]: \(response!)" : "[Response]: nil") + output.append("[TemporaryURL]: \(temporaryURL?.path ?? "nil")") + output.append("[DestinationURL]: \(destinationURL?.path ?? "nil")") + output.append("[ResumeData]: \(resumeData?.count ?? 0) bytes") + output.append("[Result]: \(result.debugDescription)") + output.append("[Timeline]: \(timeline.debugDescription)") + + return output.joined(separator: "\n") + } +} + +// MARK: - + +extension DownloadResponse { + /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped + /// result value as a parameter. + /// + /// Use the `map` method with a closure that does not throw. For example: + /// + /// let possibleData: DownloadResponse = ... + /// let possibleInt = possibleData.map { $0.count } + /// + /// - parameter transform: A closure that takes the success value of the instance's result. + /// + /// - returns: A `DownloadResponse` whose result wraps the value returned by the given closure. If this instance's + /// result is a failure, returns a response wrapping the same failure. + public func map(_ transform: (Value) -> T) -> DownloadResponse { + var response = DownloadResponse( + request: request, + response: self.response, + temporaryURL: temporaryURL, + destinationURL: destinationURL, + resumeData: resumeData, + result: result.map(transform), + timeline: timeline + ) + + response._metrics = _metrics + + return response + } + + /// Evaluates the given closure when the result of this `DownloadResponse` is a success, passing the unwrapped + /// result value as a parameter. + /// + /// Use the `flatMap` method with a closure that may throw an error. For example: + /// + /// let possibleData: DownloadResponse = ... + /// let possibleObject = possibleData.flatMap { + /// try JSONSerialization.jsonObject(with: $0) + /// } + /// + /// - parameter transform: A closure that takes the success value of the instance's result. + /// + /// - returns: A success or failure `DownloadResponse` depending on the result of the given closure. If this + /// instance's result is a failure, returns the same failure. + public func flatMap(_ transform: (Value) throws -> T) -> DownloadResponse { + var response = DownloadResponse( + request: request, + response: self.response, + temporaryURL: temporaryURL, + destinationURL: destinationURL, + resumeData: resumeData, + result: result.flatMap(transform), + timeline: timeline + ) + + response._metrics = _metrics + + return response + } + + /// Evaluates the specified closure when the `DownloadResponse` is a failure, passing the unwrapped error as a parameter. + /// + /// Use the `mapError` function with a closure that does not throw. For example: + /// + /// let possibleData: DownloadResponse = ... + /// let withMyError = possibleData.mapError { MyError.error($0) } + /// + /// - Parameter transform: A closure that takes the error of the instance. + /// - Returns: A `DownloadResponse` instance containing the result of the transform. + public func mapError(_ transform: (Error) -> E) -> DownloadResponse { + var response = DownloadResponse( + request: request, + response: self.response, + temporaryURL: temporaryURL, + destinationURL: destinationURL, + resumeData: resumeData, + result: result.mapError(transform), + timeline: timeline + ) + + response._metrics = _metrics + + return response + } + + /// Evaluates the specified closure when the `DownloadResponse` is a failure, passing the unwrapped error as a parameter. + /// + /// Use the `flatMapError` function with a closure that may throw an error. For example: + /// + /// let possibleData: DownloadResponse = ... + /// let possibleObject = possibleData.flatMapError { + /// try someFailableFunction(taking: $0) + /// } + /// + /// - Parameter transform: A throwing closure that takes the error of the instance. + /// + /// - Returns: A `DownloadResponse` instance containing the result of the transform. + public func flatMapError(_ transform: (Error) throws -> E) -> DownloadResponse { + var response = DownloadResponse( + request: request, + response: self.response, + temporaryURL: temporaryURL, + destinationURL: destinationURL, + resumeData: resumeData, + result: result.flatMapError(transform), + timeline: timeline + ) + + response._metrics = _metrics + + return response + } +} + +// MARK: - + +protocol Response { + /// The task metrics containing the request / response statistics. + var _metrics: AnyObject? { get set } + mutating func add(_ metrics: AnyObject?) +} + +extension Response { + mutating func add(_ metrics: AnyObject?) { + #if !os(watchOS) + guard #available(iOS 10.0, macOS 10.12, tvOS 10.0, *) else { return } + guard let metrics = metrics as? URLSessionTaskMetrics else { return } + + _metrics = metrics + #endif + } +} + +// MARK: - + +@available(iOS 10.0, macOS 10.12, tvOS 10.0, *) +extension DefaultDataResponse: Response { +#if !os(watchOS) + /// The task metrics containing the request / response statistics. + public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics } +#endif +} + +@available(iOS 10.0, macOS 10.12, tvOS 10.0, *) +extension DataResponse: Response { +#if !os(watchOS) + /// The task metrics containing the request / response statistics. + public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics } +#endif +} + +@available(iOS 10.0, macOS 10.12, tvOS 10.0, *) +extension DefaultDownloadResponse: Response { +#if !os(watchOS) + /// The task metrics containing the request / response statistics. + public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics } +#endif +} + +@available(iOS 10.0, macOS 10.12, tvOS 10.0, *) +extension DownloadResponse: Response { +#if !os(watchOS) + /// The task metrics containing the request / response statistics. + public var metrics: URLSessionTaskMetrics? { return _metrics as? URLSessionTaskMetrics } +#endif +} diff --git a/Pods/Alamofire/Source/ResponseSerialization.swift b/Pods/Alamofire/Source/ResponseSerialization.swift new file mode 100644 index 0000000..9cc105a --- /dev/null +++ b/Pods/Alamofire/Source/ResponseSerialization.swift @@ -0,0 +1,715 @@ +// +// ResponseSerialization.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// The type in which all data response serializers must conform to in order to serialize a response. +public protocol DataResponseSerializerProtocol { + /// The type of serialized object to be created by this `DataResponseSerializerType`. + associatedtype SerializedObject + + /// A closure used by response handlers that takes a request, response, data and error and returns a result. + var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result { get } +} + +// MARK: - + +/// A generic `DataResponseSerializerType` used to serialize a request, response, and data into a serialized object. +public struct DataResponseSerializer: DataResponseSerializerProtocol { + /// The type of serialized object to be created by this `DataResponseSerializer`. + public typealias SerializedObject = Value + + /// A closure used by response handlers that takes a request, response, data and error and returns a result. + public var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result + + /// Initializes the `ResponseSerializer` instance with the given serialize response closure. + /// + /// - parameter serializeResponse: The closure used to serialize the response. + /// + /// - returns: The new generic response serializer instance. + public init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result) { + self.serializeResponse = serializeResponse + } +} + +// MARK: - + +/// The type in which all download response serializers must conform to in order to serialize a response. +public protocol DownloadResponseSerializerProtocol { + /// The type of serialized object to be created by this `DownloadResponseSerializerType`. + associatedtype SerializedObject + + /// A closure used by response handlers that takes a request, response, url and error and returns a result. + var serializeResponse: (URLRequest?, HTTPURLResponse?, URL?, Error?) -> Result { get } +} + +// MARK: - + +/// A generic `DownloadResponseSerializerType` used to serialize a request, response, and data into a serialized object. +public struct DownloadResponseSerializer: DownloadResponseSerializerProtocol { + /// The type of serialized object to be created by this `DownloadResponseSerializer`. + public typealias SerializedObject = Value + + /// A closure used by response handlers that takes a request, response, url and error and returns a result. + public var serializeResponse: (URLRequest?, HTTPURLResponse?, URL?, Error?) -> Result + + /// Initializes the `ResponseSerializer` instance with the given serialize response closure. + /// + /// - parameter serializeResponse: The closure used to serialize the response. + /// + /// - returns: The new generic response serializer instance. + public init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, URL?, Error?) -> Result) { + self.serializeResponse = serializeResponse + } +} + +// MARK: - Timeline + +extension Request { + var timeline: Timeline { + let requestStartTime = self.startTime ?? CFAbsoluteTimeGetCurrent() + let requestCompletedTime = self.endTime ?? CFAbsoluteTimeGetCurrent() + let initialResponseTime = self.delegate.initialResponseTime ?? requestCompletedTime + + return Timeline( + requestStartTime: requestStartTime, + initialResponseTime: initialResponseTime, + requestCompletedTime: requestCompletedTime, + serializationCompletedTime: CFAbsoluteTimeGetCurrent() + ) + } +} + +// MARK: - Default + +extension DataRequest { + /// Adds a handler to be called once the request has finished. + /// + /// - parameter queue: The queue on which the completion handler is dispatched. + /// - parameter completionHandler: The code to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self { + delegate.queue.addOperation { + (queue ?? DispatchQueue.main).async { + var dataResponse = DefaultDataResponse( + request: self.request, + response: self.response, + data: self.delegate.data, + error: self.delegate.error, + timeline: self.timeline + ) + + dataResponse.add(self.delegate.metrics) + + completionHandler(dataResponse) + } + } + + return self + } + + /// Adds a handler to be called once the request has finished. + /// + /// - parameter queue: The queue on which the completion handler is dispatched. + /// - parameter responseSerializer: The response serializer responsible for serializing the request, response, + /// and data. + /// - parameter completionHandler: The code to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func response( + queue: DispatchQueue? = nil, + responseSerializer: T, + completionHandler: @escaping (DataResponse) -> Void) + -> Self + { + delegate.queue.addOperation { + let result = responseSerializer.serializeResponse( + self.request, + self.response, + self.delegate.data, + self.delegate.error + ) + + var dataResponse = DataResponse( + request: self.request, + response: self.response, + data: self.delegate.data, + result: result, + timeline: self.timeline + ) + + dataResponse.add(self.delegate.metrics) + + (queue ?? DispatchQueue.main).async { completionHandler(dataResponse) } + } + + return self + } +} + +extension DownloadRequest { + /// Adds a handler to be called once the request has finished. + /// + /// - parameter queue: The queue on which the completion handler is dispatched. + /// - parameter completionHandler: The code to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func response( + queue: DispatchQueue? = nil, + completionHandler: @escaping (DefaultDownloadResponse) -> Void) + -> Self + { + delegate.queue.addOperation { + (queue ?? DispatchQueue.main).async { + var downloadResponse = DefaultDownloadResponse( + request: self.request, + response: self.response, + temporaryURL: self.downloadDelegate.temporaryURL, + destinationURL: self.downloadDelegate.destinationURL, + resumeData: self.downloadDelegate.resumeData, + error: self.downloadDelegate.error, + timeline: self.timeline + ) + + downloadResponse.add(self.delegate.metrics) + + completionHandler(downloadResponse) + } + } + + return self + } + + /// Adds a handler to be called once the request has finished. + /// + /// - parameter queue: The queue on which the completion handler is dispatched. + /// - parameter responseSerializer: The response serializer responsible for serializing the request, response, + /// and data contained in the destination url. + /// - parameter completionHandler: The code to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func response( + queue: DispatchQueue? = nil, + responseSerializer: T, + completionHandler: @escaping (DownloadResponse) -> Void) + -> Self + { + delegate.queue.addOperation { + let result = responseSerializer.serializeResponse( + self.request, + self.response, + self.downloadDelegate.fileURL, + self.downloadDelegate.error + ) + + var downloadResponse = DownloadResponse( + request: self.request, + response: self.response, + temporaryURL: self.downloadDelegate.temporaryURL, + destinationURL: self.downloadDelegate.destinationURL, + resumeData: self.downloadDelegate.resumeData, + result: result, + timeline: self.timeline + ) + + downloadResponse.add(self.delegate.metrics) + + (queue ?? DispatchQueue.main).async { completionHandler(downloadResponse) } + } + + return self + } +} + +// MARK: - Data + +extension Request { + /// Returns a result data type that contains the response data as-is. + /// + /// - parameter response: The response from the server. + /// - parameter data: The data returned from the server. + /// - parameter error: The error already encountered if it exists. + /// + /// - returns: The result data type. + public static func serializeResponseData(response: HTTPURLResponse?, data: Data?, error: Error?) -> Result { + guard error == nil else { return .failure(error!) } + + if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(Data()) } + + guard let validData = data else { + return .failure(AFError.responseSerializationFailed(reason: .inputDataNil)) + } + + return .success(validData) + } +} + +extension DataRequest { + /// Creates a response serializer that returns the associated data as-is. + /// + /// - returns: A data response serializer. + public static func dataResponseSerializer() -> DataResponseSerializer { + return DataResponseSerializer { _, response, data, error in + return Request.serializeResponseData(response: response, data: data, error: error) + } + } + + /// Adds a handler to be called once the request has finished. + /// + /// - parameter completionHandler: The code to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func responseData( + queue: DispatchQueue? = nil, + completionHandler: @escaping (DataResponse) -> Void) + -> Self + { + return response( + queue: queue, + responseSerializer: DataRequest.dataResponseSerializer(), + completionHandler: completionHandler + ) + } +} + +extension DownloadRequest { + /// Creates a response serializer that returns the associated data as-is. + /// + /// - returns: A data response serializer. + public static func dataResponseSerializer() -> DownloadResponseSerializer { + return DownloadResponseSerializer { _, response, fileURL, error in + guard error == nil else { return .failure(error!) } + + guard let fileURL = fileURL else { + return .failure(AFError.responseSerializationFailed(reason: .inputFileNil)) + } + + do { + let data = try Data(contentsOf: fileURL) + return Request.serializeResponseData(response: response, data: data, error: error) + } catch { + return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL))) + } + } + } + + /// Adds a handler to be called once the request has finished. + /// + /// - parameter completionHandler: The code to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func responseData( + queue: DispatchQueue? = nil, + completionHandler: @escaping (DownloadResponse) -> Void) + -> Self + { + return response( + queue: queue, + responseSerializer: DownloadRequest.dataResponseSerializer(), + completionHandler: completionHandler + ) + } +} + +// MARK: - String + +extension Request { + /// Returns a result string type initialized from the response data with the specified string encoding. + /// + /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server + /// response, falling back to the default HTTP default character set, ISO-8859-1. + /// - parameter response: The response from the server. + /// - parameter data: The data returned from the server. + /// - parameter error: The error already encountered if it exists. + /// + /// - returns: The result data type. + public static func serializeResponseString( + encoding: String.Encoding?, + response: HTTPURLResponse?, + data: Data?, + error: Error?) + -> Result + { + guard error == nil else { return .failure(error!) } + + if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success("") } + + guard let validData = data else { + return .failure(AFError.responseSerializationFailed(reason: .inputDataNil)) + } + + var convertedEncoding = encoding + + if let encodingName = response?.textEncodingName as CFString?, convertedEncoding == nil { + convertedEncoding = String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding( + CFStringConvertIANACharSetNameToEncoding(encodingName)) + ) + } + + let actualEncoding = convertedEncoding ?? .isoLatin1 + + if let string = String(data: validData, encoding: actualEncoding) { + return .success(string) + } else { + return .failure(AFError.responseSerializationFailed(reason: .stringSerializationFailed(encoding: actualEncoding))) + } + } +} + +extension DataRequest { + /// Creates a response serializer that returns a result string type initialized from the response data with + /// the specified string encoding. + /// + /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server + /// response, falling back to the default HTTP default character set, ISO-8859-1. + /// + /// - returns: A string response serializer. + public static func stringResponseSerializer(encoding: String.Encoding? = nil) -> DataResponseSerializer { + return DataResponseSerializer { _, response, data, error in + return Request.serializeResponseString(encoding: encoding, response: response, data: data, error: error) + } + } + + /// Adds a handler to be called once the request has finished. + /// + /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the + /// server response, falling back to the default HTTP default character set, + /// ISO-8859-1. + /// - parameter completionHandler: A closure to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func responseString( + queue: DispatchQueue? = nil, + encoding: String.Encoding? = nil, + completionHandler: @escaping (DataResponse) -> Void) + -> Self + { + return response( + queue: queue, + responseSerializer: DataRequest.stringResponseSerializer(encoding: encoding), + completionHandler: completionHandler + ) + } +} + +extension DownloadRequest { + /// Creates a response serializer that returns a result string type initialized from the response data with + /// the specified string encoding. + /// + /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the server + /// response, falling back to the default HTTP default character set, ISO-8859-1. + /// + /// - returns: A string response serializer. + public static func stringResponseSerializer(encoding: String.Encoding? = nil) -> DownloadResponseSerializer { + return DownloadResponseSerializer { _, response, fileURL, error in + guard error == nil else { return .failure(error!) } + + guard let fileURL = fileURL else { + return .failure(AFError.responseSerializationFailed(reason: .inputFileNil)) + } + + do { + let data = try Data(contentsOf: fileURL) + return Request.serializeResponseString(encoding: encoding, response: response, data: data, error: error) + } catch { + return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL))) + } + } + } + + /// Adds a handler to be called once the request has finished. + /// + /// - parameter encoding: The string encoding. If `nil`, the string encoding will be determined from the + /// server response, falling back to the default HTTP default character set, + /// ISO-8859-1. + /// - parameter completionHandler: A closure to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func responseString( + queue: DispatchQueue? = nil, + encoding: String.Encoding? = nil, + completionHandler: @escaping (DownloadResponse) -> Void) + -> Self + { + return response( + queue: queue, + responseSerializer: DownloadRequest.stringResponseSerializer(encoding: encoding), + completionHandler: completionHandler + ) + } +} + +// MARK: - JSON + +extension Request { + /// Returns a JSON object contained in a result type constructed from the response data using `JSONSerialization` + /// with the specified reading options. + /// + /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`. + /// - parameter response: The response from the server. + /// - parameter data: The data returned from the server. + /// - parameter error: The error already encountered if it exists. + /// + /// - returns: The result data type. + public static func serializeResponseJSON( + options: JSONSerialization.ReadingOptions, + response: HTTPURLResponse?, + data: Data?, + error: Error?) + -> Result + { + guard error == nil else { return .failure(error!) } + + if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(NSNull()) } + + guard let validData = data, validData.count > 0 else { + return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)) + } + + do { + let json = try JSONSerialization.jsonObject(with: validData, options: options) + return .success(json) + } catch { + return .failure(AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error))) + } + } +} + +extension DataRequest { + /// Creates a response serializer that returns a JSON object result type constructed from the response data using + /// `JSONSerialization` with the specified reading options. + /// + /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`. + /// + /// - returns: A JSON object response serializer. + public static func jsonResponseSerializer( + options: JSONSerialization.ReadingOptions = .allowFragments) + -> DataResponseSerializer + { + return DataResponseSerializer { _, response, data, error in + return Request.serializeResponseJSON(options: options, response: response, data: data, error: error) + } + } + + /// Adds a handler to be called once the request has finished. + /// + /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`. + /// - parameter completionHandler: A closure to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func responseJSON( + queue: DispatchQueue? = nil, + options: JSONSerialization.ReadingOptions = .allowFragments, + completionHandler: @escaping (DataResponse) -> Void) + -> Self + { + return response( + queue: queue, + responseSerializer: DataRequest.jsonResponseSerializer(options: options), + completionHandler: completionHandler + ) + } +} + +extension DownloadRequest { + /// Creates a response serializer that returns a JSON object result type constructed from the response data using + /// `JSONSerialization` with the specified reading options. + /// + /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`. + /// + /// - returns: A JSON object response serializer. + public static func jsonResponseSerializer( + options: JSONSerialization.ReadingOptions = .allowFragments) + -> DownloadResponseSerializer + { + return DownloadResponseSerializer { _, response, fileURL, error in + guard error == nil else { return .failure(error!) } + + guard let fileURL = fileURL else { + return .failure(AFError.responseSerializationFailed(reason: .inputFileNil)) + } + + do { + let data = try Data(contentsOf: fileURL) + return Request.serializeResponseJSON(options: options, response: response, data: data, error: error) + } catch { + return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL))) + } + } + } + + /// Adds a handler to be called once the request has finished. + /// + /// - parameter options: The JSON serialization reading options. Defaults to `.allowFragments`. + /// - parameter completionHandler: A closure to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func responseJSON( + queue: DispatchQueue? = nil, + options: JSONSerialization.ReadingOptions = .allowFragments, + completionHandler: @escaping (DownloadResponse) -> Void) + -> Self + { + return response( + queue: queue, + responseSerializer: DownloadRequest.jsonResponseSerializer(options: options), + completionHandler: completionHandler + ) + } +} + +// MARK: - Property List + +extension Request { + /// Returns a plist object contained in a result type constructed from the response data using + /// `PropertyListSerialization` with the specified reading options. + /// + /// - parameter options: The property list reading options. Defaults to `[]`. + /// - parameter response: The response from the server. + /// - parameter data: The data returned from the server. + /// - parameter error: The error already encountered if it exists. + /// + /// - returns: The result data type. + public static func serializeResponsePropertyList( + options: PropertyListSerialization.ReadOptions, + response: HTTPURLResponse?, + data: Data?, + error: Error?) + -> Result + { + guard error == nil else { return .failure(error!) } + + if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(NSNull()) } + + guard let validData = data, validData.count > 0 else { + return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)) + } + + do { + let plist = try PropertyListSerialization.propertyList(from: validData, options: options, format: nil) + return .success(plist) + } catch { + return .failure(AFError.responseSerializationFailed(reason: .propertyListSerializationFailed(error: error))) + } + } +} + +extension DataRequest { + /// Creates a response serializer that returns an object constructed from the response data using + /// `PropertyListSerialization` with the specified reading options. + /// + /// - parameter options: The property list reading options. Defaults to `[]`. + /// + /// - returns: A property list object response serializer. + public static func propertyListResponseSerializer( + options: PropertyListSerialization.ReadOptions = []) + -> DataResponseSerializer + { + return DataResponseSerializer { _, response, data, error in + return Request.serializeResponsePropertyList(options: options, response: response, data: data, error: error) + } + } + + /// Adds a handler to be called once the request has finished. + /// + /// - parameter options: The property list reading options. Defaults to `[]`. + /// - parameter completionHandler: A closure to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func responsePropertyList( + queue: DispatchQueue? = nil, + options: PropertyListSerialization.ReadOptions = [], + completionHandler: @escaping (DataResponse) -> Void) + -> Self + { + return response( + queue: queue, + responseSerializer: DataRequest.propertyListResponseSerializer(options: options), + completionHandler: completionHandler + ) + } +} + +extension DownloadRequest { + /// Creates a response serializer that returns an object constructed from the response data using + /// `PropertyListSerialization` with the specified reading options. + /// + /// - parameter options: The property list reading options. Defaults to `[]`. + /// + /// - returns: A property list object response serializer. + public static func propertyListResponseSerializer( + options: PropertyListSerialization.ReadOptions = []) + -> DownloadResponseSerializer + { + return DownloadResponseSerializer { _, response, fileURL, error in + guard error == nil else { return .failure(error!) } + + guard let fileURL = fileURL else { + return .failure(AFError.responseSerializationFailed(reason: .inputFileNil)) + } + + do { + let data = try Data(contentsOf: fileURL) + return Request.serializeResponsePropertyList(options: options, response: response, data: data, error: error) + } catch { + return .failure(AFError.responseSerializationFailed(reason: .inputFileReadFailed(at: fileURL))) + } + } + } + + /// Adds a handler to be called once the request has finished. + /// + /// - parameter options: The property list reading options. Defaults to `[]`. + /// - parameter completionHandler: A closure to be executed once the request has finished. + /// + /// - returns: The request. + @discardableResult + public func responsePropertyList( + queue: DispatchQueue? = nil, + options: PropertyListSerialization.ReadOptions = [], + completionHandler: @escaping (DownloadResponse) -> Void) + -> Self + { + return response( + queue: queue, + responseSerializer: DownloadRequest.propertyListResponseSerializer(options: options), + completionHandler: completionHandler + ) + } +} + +/// A set of HTTP response status code that do not contain response data. +private let emptyDataStatusCodes: Set = [204, 205] diff --git a/Pods/Alamofire/Source/Result.swift b/Pods/Alamofire/Source/Result.swift new file mode 100644 index 0000000..e092808 --- /dev/null +++ b/Pods/Alamofire/Source/Result.swift @@ -0,0 +1,300 @@ +// +// Result.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// Used to represent whether a request was successful or encountered an error. +/// +/// - success: The request and all post processing operations were successful resulting in the serialization of the +/// provided associated value. +/// +/// - failure: The request encountered an error resulting in a failure. The associated values are the original data +/// provided by the server as well as the error that caused the failure. +public enum Result { + case success(Value) + case failure(Error) + + /// Returns `true` if the result is a success, `false` otherwise. + public var isSuccess: Bool { + switch self { + case .success: + return true + case .failure: + return false + } + } + + /// Returns `true` if the result is a failure, `false` otherwise. + public var isFailure: Bool { + return !isSuccess + } + + /// Returns the associated value if the result is a success, `nil` otherwise. + public var value: Value? { + switch self { + case .success(let value): + return value + case .failure: + return nil + } + } + + /// Returns the associated error value if the result is a failure, `nil` otherwise. + public var error: Error? { + switch self { + case .success: + return nil + case .failure(let error): + return error + } + } +} + +// MARK: - CustomStringConvertible + +extension Result: CustomStringConvertible { + /// The textual representation used when written to an output stream, which includes whether the result was a + /// success or failure. + public var description: String { + switch self { + case .success: + return "SUCCESS" + case .failure: + return "FAILURE" + } + } +} + +// MARK: - CustomDebugStringConvertible + +extension Result: CustomDebugStringConvertible { + /// The debug textual representation used when written to an output stream, which includes whether the result was a + /// success or failure in addition to the value or error. + public var debugDescription: String { + switch self { + case .success(let value): + return "SUCCESS: \(value)" + case .failure(let error): + return "FAILURE: \(error)" + } + } +} + +// MARK: - Functional APIs + +extension Result { + /// Creates a `Result` instance from the result of a closure. + /// + /// A failure result is created when the closure throws, and a success result is created when the closure + /// succeeds without throwing an error. + /// + /// func someString() throws -> String { ... } + /// + /// let result = Result(value: { + /// return try someString() + /// }) + /// + /// // The type of result is Result + /// + /// The trailing closure syntax is also supported: + /// + /// let result = Result { try someString() } + /// + /// - parameter value: The closure to execute and create the result for. + public init(value: () throws -> Value) { + do { + self = try .success(value()) + } catch { + self = .failure(error) + } + } + + /// Returns the success value, or throws the failure error. + /// + /// let possibleString: Result = .success("success") + /// try print(possibleString.unwrap()) + /// // Prints "success" + /// + /// let noString: Result = .failure(error) + /// try print(noString.unwrap()) + /// // Throws error + public func unwrap() throws -> Value { + switch self { + case .success(let value): + return value + case .failure(let error): + throw error + } + } + + /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter. + /// + /// Use the `map` method with a closure that does not throw. For example: + /// + /// let possibleData: Result = .success(Data()) + /// let possibleInt = possibleData.map { $0.count } + /// try print(possibleInt.unwrap()) + /// // Prints "0" + /// + /// let noData: Result = .failure(error) + /// let noInt = noData.map { $0.count } + /// try print(noInt.unwrap()) + /// // Throws error + /// + /// - parameter transform: A closure that takes the success value of the `Result` instance. + /// + /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the + /// same failure. + public func map(_ transform: (Value) -> T) -> Result { + switch self { + case .success(let value): + return .success(transform(value)) + case .failure(let error): + return .failure(error) + } + } + + /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter. + /// + /// Use the `flatMap` method with a closure that may throw an error. For example: + /// + /// let possibleData: Result = .success(Data(...)) + /// let possibleObject = possibleData.flatMap { + /// try JSONSerialization.jsonObject(with: $0) + /// } + /// + /// - parameter transform: A closure that takes the success value of the instance. + /// + /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the + /// same failure. + public func flatMap(_ transform: (Value) throws -> T) -> Result { + switch self { + case .success(let value): + do { + return try .success(transform(value)) + } catch { + return .failure(error) + } + case .failure(let error): + return .failure(error) + } + } + + /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter. + /// + /// Use the `mapError` function with a closure that does not throw. For example: + /// + /// let possibleData: Result = .failure(someError) + /// let withMyError: Result = possibleData.mapError { MyError.error($0) } + /// + /// - Parameter transform: A closure that takes the error of the instance. + /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns + /// the same instance. + public func mapError(_ transform: (Error) -> T) -> Result { + switch self { + case .failure(let error): + return .failure(transform(error)) + case .success: + return self + } + } + + /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter. + /// + /// Use the `flatMapError` function with a closure that may throw an error. For example: + /// + /// let possibleData: Result = .success(Data(...)) + /// let possibleObject = possibleData.flatMapError { + /// try someFailableFunction(taking: $0) + /// } + /// + /// - Parameter transform: A throwing closure that takes the error of the instance. + /// + /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns + /// the same instance. + public func flatMapError(_ transform: (Error) throws -> T) -> Result { + switch self { + case .failure(let error): + do { + return try .failure(transform(error)) + } catch { + return .failure(error) + } + case .success: + return self + } + } + + /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter. + /// + /// Use the `withValue` function to evaluate the passed closure without modifying the `Result` instance. + /// + /// - Parameter closure: A closure that takes the success value of this instance. + /// - Returns: This `Result` instance, unmodified. + @discardableResult + public func withValue(_ closure: (Value) throws -> Void) rethrows -> Result { + if case let .success(value) = self { try closure(value) } + + return self + } + + /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter. + /// + /// Use the `withError` function to evaluate the passed closure without modifying the `Result` instance. + /// + /// - Parameter closure: A closure that takes the success value of this instance. + /// - Returns: This `Result` instance, unmodified. + @discardableResult + public func withError(_ closure: (Error) throws -> Void) rethrows -> Result { + if case let .failure(error) = self { try closure(error) } + + return self + } + + /// Evaluates the specified closure when the `Result` is a success. + /// + /// Use the `ifSuccess` function to evaluate the passed closure without modifying the `Result` instance. + /// + /// - Parameter closure: A `Void` closure. + /// - Returns: This `Result` instance, unmodified. + @discardableResult + public func ifSuccess(_ closure: () throws -> Void) rethrows -> Result { + if isSuccess { try closure() } + + return self + } + + /// Evaluates the specified closure when the `Result` is a failure. + /// + /// Use the `ifFailure` function to evaluate the passed closure without modifying the `Result` instance. + /// + /// - Parameter closure: A `Void` closure. + /// - Returns: This `Result` instance, unmodified. + @discardableResult + public func ifFailure(_ closure: () throws -> Void) rethrows -> Result { + if isFailure { try closure() } + + return self + } +} diff --git a/Pods/Alamofire/Source/ServerTrustPolicy.swift b/Pods/Alamofire/Source/ServerTrustPolicy.swift new file mode 100644 index 0000000..dea099e --- /dev/null +++ b/Pods/Alamofire/Source/ServerTrustPolicy.swift @@ -0,0 +1,307 @@ +// +// ServerTrustPolicy.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// Responsible for managing the mapping of `ServerTrustPolicy` objects to a given host. +open class ServerTrustPolicyManager { + /// The dictionary of policies mapped to a particular host. + public let policies: [String: ServerTrustPolicy] + + /// Initializes the `ServerTrustPolicyManager` instance with the given policies. + /// + /// Since different servers and web services can have different leaf certificates, intermediate and even root + /// certficates, it is important to have the flexibility to specify evaluation policies on a per host basis. This + /// allows for scenarios such as using default evaluation for host1, certificate pinning for host2, public key + /// pinning for host3 and disabling evaluation for host4. + /// + /// - parameter policies: A dictionary of all policies mapped to a particular host. + /// + /// - returns: The new `ServerTrustPolicyManager` instance. + public init(policies: [String: ServerTrustPolicy]) { + self.policies = policies + } + + /// Returns the `ServerTrustPolicy` for the given host if applicable. + /// + /// By default, this method will return the policy that perfectly matches the given host. Subclasses could override + /// this method and implement more complex mapping implementations such as wildcards. + /// + /// - parameter host: The host to use when searching for a matching policy. + /// + /// - returns: The server trust policy for the given host if found. + open func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? { + return policies[host] + } +} + +// MARK: - + +extension URLSession { + private struct AssociatedKeys { + static var managerKey = "URLSession.ServerTrustPolicyManager" + } + + var serverTrustPolicyManager: ServerTrustPolicyManager? { + get { + return objc_getAssociatedObject(self, &AssociatedKeys.managerKey) as? ServerTrustPolicyManager + } + set (manager) { + objc_setAssociatedObject(self, &AssociatedKeys.managerKey, manager, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } +} + +// MARK: - ServerTrustPolicy + +/// The `ServerTrustPolicy` evaluates the server trust generally provided by an `NSURLAuthenticationChallenge` when +/// connecting to a server over a secure HTTPS connection. The policy configuration then evaluates the server trust +/// with a given set of criteria to determine whether the server trust is valid and the connection should be made. +/// +/// Using pinned certificates or public keys for evaluation helps prevent man-in-the-middle (MITM) attacks and other +/// vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged +/// to route all communication over an HTTPS connection with pinning enabled. +/// +/// - performDefaultEvaluation: Uses the default server trust evaluation while allowing you to control whether to +/// validate the host provided by the challenge. Applications are encouraged to always +/// validate the host in production environments to guarantee the validity of the server's +/// certificate chain. +/// +/// - performRevokedEvaluation: Uses the default and revoked server trust evaluations allowing you to control whether to +/// validate the host provided by the challenge as well as specify the revocation flags for +/// testing for revoked certificates. Apple platforms did not start testing for revoked +/// certificates automatically until iOS 10.1, macOS 10.12 and tvOS 10.1 which is +/// demonstrated in our TLS tests. Applications are encouraged to always validate the host +/// in production environments to guarantee the validity of the server's certificate chain. +/// +/// - pinCertificates: Uses the pinned certificates to validate the server trust. The server trust is +/// considered valid if one of the pinned certificates match one of the server certificates. +/// By validating both the certificate chain and host, certificate pinning provides a very +/// secure form of server trust validation mitigating most, if not all, MITM attacks. +/// Applications are encouraged to always validate the host and require a valid certificate +/// chain in production environments. +/// +/// - pinPublicKeys: Uses the pinned public keys to validate the server trust. The server trust is considered +/// valid if one of the pinned public keys match one of the server certificate public keys. +/// By validating both the certificate chain and host, public key pinning provides a very +/// secure form of server trust validation mitigating most, if not all, MITM attacks. +/// Applications are encouraged to always validate the host and require a valid certificate +/// chain in production environments. +/// +/// - disableEvaluation: Disables all evaluation which in turn will always consider any server trust as valid. +/// +/// - customEvaluation: Uses the associated closure to evaluate the validity of the server trust. +public enum ServerTrustPolicy { + case performDefaultEvaluation(validateHost: Bool) + case performRevokedEvaluation(validateHost: Bool, revocationFlags: CFOptionFlags) + case pinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool) + case pinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool) + case disableEvaluation + case customEvaluation((_ serverTrust: SecTrust, _ host: String) -> Bool) + + // MARK: - Bundle Location + + /// Returns all certificates within the given bundle with a `.cer` file extension. + /// + /// - parameter bundle: The bundle to search for all `.cer` files. + /// + /// - returns: All certificates within the given bundle. + public static func certificates(in bundle: Bundle = Bundle.main) -> [SecCertificate] { + var certificates: [SecCertificate] = [] + + let paths = Set([".cer", ".CER", ".crt", ".CRT", ".der", ".DER"].map { fileExtension in + bundle.paths(forResourcesOfType: fileExtension, inDirectory: nil) + }.joined()) + + for path in paths { + if + let certificateData = try? Data(contentsOf: URL(fileURLWithPath: path)) as CFData, + let certificate = SecCertificateCreateWithData(nil, certificateData) + { + certificates.append(certificate) + } + } + + return certificates + } + + /// Returns all public keys within the given bundle with a `.cer` file extension. + /// + /// - parameter bundle: The bundle to search for all `*.cer` files. + /// + /// - returns: All public keys within the given bundle. + public static func publicKeys(in bundle: Bundle = Bundle.main) -> [SecKey] { + var publicKeys: [SecKey] = [] + + for certificate in certificates(in: bundle) { + if let publicKey = publicKey(for: certificate) { + publicKeys.append(publicKey) + } + } + + return publicKeys + } + + // MARK: - Evaluation + + /// Evaluates whether the server trust is valid for the given host. + /// + /// - parameter serverTrust: The server trust to evaluate. + /// - parameter host: The host of the challenge protection space. + /// + /// - returns: Whether the server trust is valid. + public func evaluate(_ serverTrust: SecTrust, forHost host: String) -> Bool { + var serverTrustIsValid = false + + switch self { + case let .performDefaultEvaluation(validateHost): + let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) + SecTrustSetPolicies(serverTrust, policy) + + serverTrustIsValid = trustIsValid(serverTrust) + case let .performRevokedEvaluation(validateHost, revocationFlags): + let defaultPolicy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) + let revokedPolicy = SecPolicyCreateRevocation(revocationFlags) + SecTrustSetPolicies(serverTrust, [defaultPolicy, revokedPolicy] as CFTypeRef) + + serverTrustIsValid = trustIsValid(serverTrust) + case let .pinCertificates(pinnedCertificates, validateCertificateChain, validateHost): + if validateCertificateChain { + let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) + SecTrustSetPolicies(serverTrust, policy) + + SecTrustSetAnchorCertificates(serverTrust, pinnedCertificates as CFArray) + SecTrustSetAnchorCertificatesOnly(serverTrust, true) + + serverTrustIsValid = trustIsValid(serverTrust) + } else { + let serverCertificatesDataArray = certificateData(for: serverTrust) + let pinnedCertificatesDataArray = certificateData(for: pinnedCertificates) + + outerLoop: for serverCertificateData in serverCertificatesDataArray { + for pinnedCertificateData in pinnedCertificatesDataArray { + if serverCertificateData == pinnedCertificateData { + serverTrustIsValid = true + break outerLoop + } + } + } + } + case let .pinPublicKeys(pinnedPublicKeys, validateCertificateChain, validateHost): + var certificateChainEvaluationPassed = true + + if validateCertificateChain { + let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil) + SecTrustSetPolicies(serverTrust, policy) + + certificateChainEvaluationPassed = trustIsValid(serverTrust) + } + + if certificateChainEvaluationPassed { + outerLoop: for serverPublicKey in ServerTrustPolicy.publicKeys(for: serverTrust) as [AnyObject] { + for pinnedPublicKey in pinnedPublicKeys as [AnyObject] { + if serverPublicKey.isEqual(pinnedPublicKey) { + serverTrustIsValid = true + break outerLoop + } + } + } + } + case .disableEvaluation: + serverTrustIsValid = true + case let .customEvaluation(closure): + serverTrustIsValid = closure(serverTrust, host) + } + + return serverTrustIsValid + } + + // MARK: - Private - Trust Validation + + private func trustIsValid(_ trust: SecTrust) -> Bool { + var isValid = false + + var result = SecTrustResultType.invalid + let status = SecTrustEvaluate(trust, &result) + + if status == errSecSuccess { + let unspecified = SecTrustResultType.unspecified + let proceed = SecTrustResultType.proceed + + + isValid = result == unspecified || result == proceed + } + + return isValid + } + + // MARK: - Private - Certificate Data + + private func certificateData(for trust: SecTrust) -> [Data] { + var certificates: [SecCertificate] = [] + + for index in 0.. [Data] { + return certificates.map { SecCertificateCopyData($0) as Data } + } + + // MARK: - Private - Public Key Extraction + + private static func publicKeys(for trust: SecTrust) -> [SecKey] { + var publicKeys: [SecKey] = [] + + for index in 0.. SecKey? { + var publicKey: SecKey? + + let policy = SecPolicyCreateBasicX509() + var trust: SecTrust? + let trustCreationStatus = SecTrustCreateWithCertificates(certificate, policy, &trust) + + if let trust = trust, trustCreationStatus == errSecSuccess { + publicKey = SecTrustCopyPublicKey(trust) + } + + return publicKey + } +} diff --git a/Pods/Alamofire/Source/SessionDelegate.swift b/Pods/Alamofire/Source/SessionDelegate.swift new file mode 100644 index 0000000..4964f1e --- /dev/null +++ b/Pods/Alamofire/Source/SessionDelegate.swift @@ -0,0 +1,725 @@ +// +// SessionDelegate.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// Responsible for handling all delegate callbacks for the underlying session. +open class SessionDelegate: NSObject { + + // MARK: URLSessionDelegate Overrides + + /// Overrides default behavior for URLSessionDelegate method `urlSession(_:didBecomeInvalidWithError:)`. + open var sessionDidBecomeInvalidWithError: ((URLSession, Error?) -> Void)? + + /// Overrides default behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)`. + open var sessionDidReceiveChallenge: ((URLSession, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + + /// Overrides all behavior for URLSessionDelegate method `urlSession(_:didReceive:completionHandler:)` and requires the caller to call the `completionHandler`. + open var sessionDidReceiveChallengeWithCompletion: ((URLSession, URLAuthenticationChallenge, @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void)? + + /// Overrides default behavior for URLSessionDelegate method `urlSessionDidFinishEvents(forBackgroundURLSession:)`. + open var sessionDidFinishEventsForBackgroundURLSession: ((URLSession) -> Void)? + + // MARK: URLSessionTaskDelegate Overrides + + /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)`. + open var taskWillPerformHTTPRedirection: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest) -> URLRequest?)? + + /// Overrides all behavior for URLSessionTaskDelegate method `urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)` and + /// requires the caller to call the `completionHandler`. + open var taskWillPerformHTTPRedirectionWithCompletion: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest, @escaping (URLRequest?) -> Void) -> Void)? + + /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:didReceive:completionHandler:)`. + open var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + + /// Overrides all behavior for URLSessionTaskDelegate method `urlSession(_:task:didReceive:completionHandler:)` and + /// requires the caller to call the `completionHandler`. + open var taskDidReceiveChallengeWithCompletion: ((URLSession, URLSessionTask, URLAuthenticationChallenge, @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void)? + + /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:needNewBodyStream:)`. + open var taskNeedNewBodyStream: ((URLSession, URLSessionTask) -> InputStream?)? + + /// Overrides all behavior for URLSessionTaskDelegate method `urlSession(_:task:needNewBodyStream:)` and + /// requires the caller to call the `completionHandler`. + open var taskNeedNewBodyStreamWithCompletion: ((URLSession, URLSessionTask, @escaping (InputStream?) -> Void) -> Void)? + + /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)`. + open var taskDidSendBodyData: ((URLSession, URLSessionTask, Int64, Int64, Int64) -> Void)? + + /// Overrides default behavior for URLSessionTaskDelegate method `urlSession(_:task:didCompleteWithError:)`. + open var taskDidComplete: ((URLSession, URLSessionTask, Error?) -> Void)? + + // MARK: URLSessionDataDelegate Overrides + + /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didReceive:completionHandler:)`. + open var dataTaskDidReceiveResponse: ((URLSession, URLSessionDataTask, URLResponse) -> URLSession.ResponseDisposition)? + + /// Overrides all behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didReceive:completionHandler:)` and + /// requires caller to call the `completionHandler`. + open var dataTaskDidReceiveResponseWithCompletion: ((URLSession, URLSessionDataTask, URLResponse, @escaping (URLSession.ResponseDisposition) -> Void) -> Void)? + + /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didBecome:)`. + open var dataTaskDidBecomeDownloadTask: ((URLSession, URLSessionDataTask, URLSessionDownloadTask) -> Void)? + + /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:didReceive:)`. + open var dataTaskDidReceiveData: ((URLSession, URLSessionDataTask, Data) -> Void)? + + /// Overrides default behavior for URLSessionDataDelegate method `urlSession(_:dataTask:willCacheResponse:completionHandler:)`. + open var dataTaskWillCacheResponse: ((URLSession, URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)? + + /// Overrides all behavior for URLSessionDataDelegate method `urlSession(_:dataTask:willCacheResponse:completionHandler:)` and + /// requires caller to call the `completionHandler`. + open var dataTaskWillCacheResponseWithCompletion: ((URLSession, URLSessionDataTask, CachedURLResponse, @escaping (CachedURLResponse?) -> Void) -> Void)? + + // MARK: URLSessionDownloadDelegate Overrides + + /// Overrides default behavior for URLSessionDownloadDelegate method `urlSession(_:downloadTask:didFinishDownloadingTo:)`. + open var downloadTaskDidFinishDownloadingToURL: ((URLSession, URLSessionDownloadTask, URL) -> Void)? + + /// Overrides default behavior for URLSessionDownloadDelegate method `urlSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)`. + open var downloadTaskDidWriteData: ((URLSession, URLSessionDownloadTask, Int64, Int64, Int64) -> Void)? + + /// Overrides default behavior for URLSessionDownloadDelegate method `urlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:)`. + open var downloadTaskDidResumeAtOffset: ((URLSession, URLSessionDownloadTask, Int64, Int64) -> Void)? + + // MARK: URLSessionStreamDelegate Overrides + +#if !os(watchOS) + + /// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:readClosedFor:)`. + @available(iOS 9.0, macOS 10.11, tvOS 9.0, *) + open var streamTaskReadClosed: ((URLSession, URLSessionStreamTask) -> Void)? { + get { + return _streamTaskReadClosed as? (URLSession, URLSessionStreamTask) -> Void + } + set { + _streamTaskReadClosed = newValue + } + } + + /// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:writeClosedFor:)`. + @available(iOS 9.0, macOS 10.11, tvOS 9.0, *) + open var streamTaskWriteClosed: ((URLSession, URLSessionStreamTask) -> Void)? { + get { + return _streamTaskWriteClosed as? (URLSession, URLSessionStreamTask) -> Void + } + set { + _streamTaskWriteClosed = newValue + } + } + + /// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:betterRouteDiscoveredFor:)`. + @available(iOS 9.0, macOS 10.11, tvOS 9.0, *) + open var streamTaskBetterRouteDiscovered: ((URLSession, URLSessionStreamTask) -> Void)? { + get { + return _streamTaskBetterRouteDiscovered as? (URLSession, URLSessionStreamTask) -> Void + } + set { + _streamTaskBetterRouteDiscovered = newValue + } + } + + /// Overrides default behavior for URLSessionStreamDelegate method `urlSession(_:streamTask:didBecome:outputStream:)`. + @available(iOS 9.0, macOS 10.11, tvOS 9.0, *) + open var streamTaskDidBecomeInputAndOutputStreams: ((URLSession, URLSessionStreamTask, InputStream, OutputStream) -> Void)? { + get { + return _streamTaskDidBecomeInputStream as? (URLSession, URLSessionStreamTask, InputStream, OutputStream) -> Void + } + set { + _streamTaskDidBecomeInputStream = newValue + } + } + + var _streamTaskReadClosed: Any? + var _streamTaskWriteClosed: Any? + var _streamTaskBetterRouteDiscovered: Any? + var _streamTaskDidBecomeInputStream: Any? + +#endif + + // MARK: Properties + + var retrier: RequestRetrier? + weak var sessionManager: SessionManager? + + var requests: [Int: Request] = [:] + private let lock = NSLock() + + /// Access the task delegate for the specified task in a thread-safe manner. + open subscript(task: URLSessionTask) -> Request? { + get { + lock.lock() ; defer { lock.unlock() } + return requests[task.taskIdentifier] + } + set { + lock.lock() ; defer { lock.unlock() } + requests[task.taskIdentifier] = newValue + } + } + + // MARK: Lifecycle + + /// Initializes the `SessionDelegate` instance. + /// + /// - returns: The new `SessionDelegate` instance. + public override init() { + super.init() + } + + // MARK: NSObject Overrides + + /// Returns a `Bool` indicating whether the `SessionDelegate` implements or inherits a method that can respond + /// to a specified message. + /// + /// - parameter selector: A selector that identifies a message. + /// + /// - returns: `true` if the receiver implements or inherits a method that can respond to selector, otherwise `false`. + open override func responds(to selector: Selector) -> Bool { + #if !os(macOS) + if selector == #selector(URLSessionDelegate.urlSessionDidFinishEvents(forBackgroundURLSession:)) { + return sessionDidFinishEventsForBackgroundURLSession != nil + } + #endif + + #if !os(watchOS) + if #available(iOS 9.0, macOS 10.11, tvOS 9.0, *) { + switch selector { + case #selector(URLSessionStreamDelegate.urlSession(_:readClosedFor:)): + return streamTaskReadClosed != nil + case #selector(URLSessionStreamDelegate.urlSession(_:writeClosedFor:)): + return streamTaskWriteClosed != nil + case #selector(URLSessionStreamDelegate.urlSession(_:betterRouteDiscoveredFor:)): + return streamTaskBetterRouteDiscovered != nil + case #selector(URLSessionStreamDelegate.urlSession(_:streamTask:didBecome:outputStream:)): + return streamTaskDidBecomeInputAndOutputStreams != nil + default: + break + } + } + #endif + + switch selector { + case #selector(URLSessionDelegate.urlSession(_:didBecomeInvalidWithError:)): + return sessionDidBecomeInvalidWithError != nil + case #selector(URLSessionDelegate.urlSession(_:didReceive:completionHandler:)): + return (sessionDidReceiveChallenge != nil || sessionDidReceiveChallengeWithCompletion != nil) + case #selector(URLSessionTaskDelegate.urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)): + return (taskWillPerformHTTPRedirection != nil || taskWillPerformHTTPRedirectionWithCompletion != nil) + case #selector(URLSessionDataDelegate.urlSession(_:dataTask:didReceive:completionHandler:)): + return (dataTaskDidReceiveResponse != nil || dataTaskDidReceiveResponseWithCompletion != nil) + default: + return type(of: self).instancesRespond(to: selector) + } + } +} + +// MARK: - URLSessionDelegate + +extension SessionDelegate: URLSessionDelegate { + /// Tells the delegate that the session has been invalidated. + /// + /// - parameter session: The session object that was invalidated. + /// - parameter error: The error that caused invalidation, or nil if the invalidation was explicit. + open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) { + sessionDidBecomeInvalidWithError?(session, error) + } + + /// Requests credentials from the delegate in response to a session-level authentication request from the + /// remote server. + /// + /// - parameter session: The session containing the task that requested authentication. + /// - parameter challenge: An object that contains the request for authentication. + /// - parameter completionHandler: A handler that your delegate method must call providing the disposition + /// and credential. + open func urlSession( + _ session: URLSession, + didReceive challenge: URLAuthenticationChallenge, + completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) + { + guard sessionDidReceiveChallengeWithCompletion == nil else { + sessionDidReceiveChallengeWithCompletion?(session, challenge, completionHandler) + return + } + + var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling + var credential: URLCredential? + + if let sessionDidReceiveChallenge = sessionDidReceiveChallenge { + (disposition, credential) = sessionDidReceiveChallenge(session, challenge) + } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { + let host = challenge.protectionSpace.host + + if + let serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicy(forHost: host), + let serverTrust = challenge.protectionSpace.serverTrust + { + if serverTrustPolicy.evaluate(serverTrust, forHost: host) { + disposition = .useCredential + credential = URLCredential(trust: serverTrust) + } else { + disposition = .cancelAuthenticationChallenge + } + } + } + + completionHandler(disposition, credential) + } + +#if !os(macOS) + + /// Tells the delegate that all messages enqueued for a session have been delivered. + /// + /// - parameter session: The session that no longer has any outstanding requests. + open func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { + sessionDidFinishEventsForBackgroundURLSession?(session) + } + +#endif +} + +// MARK: - URLSessionTaskDelegate + +extension SessionDelegate: URLSessionTaskDelegate { + /// Tells the delegate that the remote server requested an HTTP redirect. + /// + /// - parameter session: The session containing the task whose request resulted in a redirect. + /// - parameter task: The task whose request resulted in a redirect. + /// - parameter response: An object containing the server’s response to the original request. + /// - parameter request: A URL request object filled out with the new location. + /// - parameter completionHandler: A closure that your handler should call with either the value of the request + /// parameter, a modified URL request object, or NULL to refuse the redirect and + /// return the body of the redirect response. + open func urlSession( + _ session: URLSession, + task: URLSessionTask, + willPerformHTTPRedirection response: HTTPURLResponse, + newRequest request: URLRequest, + completionHandler: @escaping (URLRequest?) -> Void) + { + guard taskWillPerformHTTPRedirectionWithCompletion == nil else { + taskWillPerformHTTPRedirectionWithCompletion?(session, task, response, request, completionHandler) + return + } + + var redirectRequest: URLRequest? = request + + if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection { + redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request) + } + + completionHandler(redirectRequest) + } + + /// Requests credentials from the delegate in response to an authentication request from the remote server. + /// + /// - parameter session: The session containing the task whose request requires authentication. + /// - parameter task: The task whose request requires authentication. + /// - parameter challenge: An object that contains the request for authentication. + /// - parameter completionHandler: A handler that your delegate method must call providing the disposition + /// and credential. + open func urlSession( + _ session: URLSession, + task: URLSessionTask, + didReceive challenge: URLAuthenticationChallenge, + completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) + { + guard taskDidReceiveChallengeWithCompletion == nil else { + taskDidReceiveChallengeWithCompletion?(session, task, challenge, completionHandler) + return + } + + if let taskDidReceiveChallenge = taskDidReceiveChallenge { + let result = taskDidReceiveChallenge(session, task, challenge) + completionHandler(result.0, result.1) + } else if let delegate = self[task]?.delegate { + delegate.urlSession( + session, + task: task, + didReceive: challenge, + completionHandler: completionHandler + ) + } else { + urlSession(session, didReceive: challenge, completionHandler: completionHandler) + } + } + + /// Tells the delegate when a task requires a new request body stream to send to the remote server. + /// + /// - parameter session: The session containing the task that needs a new body stream. + /// - parameter task: The task that needs a new body stream. + /// - parameter completionHandler: A completion handler that your delegate method should call with the new body stream. + open func urlSession( + _ session: URLSession, + task: URLSessionTask, + needNewBodyStream completionHandler: @escaping (InputStream?) -> Void) + { + guard taskNeedNewBodyStreamWithCompletion == nil else { + taskNeedNewBodyStreamWithCompletion?(session, task, completionHandler) + return + } + + if let taskNeedNewBodyStream = taskNeedNewBodyStream { + completionHandler(taskNeedNewBodyStream(session, task)) + } else if let delegate = self[task]?.delegate { + delegate.urlSession(session, task: task, needNewBodyStream: completionHandler) + } + } + + /// Periodically informs the delegate of the progress of sending body content to the server. + /// + /// - parameter session: The session containing the data task. + /// - parameter task: The data task. + /// - parameter bytesSent: The number of bytes sent since the last time this delegate method was called. + /// - parameter totalBytesSent: The total number of bytes sent so far. + /// - parameter totalBytesExpectedToSend: The expected length of the body data. + open func urlSession( + _ session: URLSession, + task: URLSessionTask, + didSendBodyData bytesSent: Int64, + totalBytesSent: Int64, + totalBytesExpectedToSend: Int64) + { + if let taskDidSendBodyData = taskDidSendBodyData { + taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend) + } else if let delegate = self[task]?.delegate as? UploadTaskDelegate { + delegate.URLSession( + session, + task: task, + didSendBodyData: bytesSent, + totalBytesSent: totalBytesSent, + totalBytesExpectedToSend: totalBytesExpectedToSend + ) + } + } + +#if !os(watchOS) + + /// Tells the delegate that the session finished collecting metrics for the task. + /// + /// - parameter session: The session collecting the metrics. + /// - parameter task: The task whose metrics have been collected. + /// - parameter metrics: The collected metrics. + @available(iOS 10.0, macOS 10.12, tvOS 10.0, *) + @objc(URLSession:task:didFinishCollectingMetrics:) + open func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) { + self[task]?.delegate.metrics = metrics + } + +#endif + + /// Tells the delegate that the task finished transferring data. + /// + /// - parameter session: The session containing the task whose request finished transferring data. + /// - parameter task: The task whose request finished transferring data. + /// - parameter error: If an error occurred, an error object indicating how the transfer failed, otherwise nil. + open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { + /// Executed after it is determined that the request is not going to be retried + let completeTask: (URLSession, URLSessionTask, Error?) -> Void = { [weak self] session, task, error in + guard let strongSelf = self else { return } + + strongSelf.taskDidComplete?(session, task, error) + + strongSelf[task]?.delegate.urlSession(session, task: task, didCompleteWithError: error) + + var userInfo: [String: Any] = [Notification.Key.Task: task] + + if let data = (strongSelf[task]?.delegate as? DataTaskDelegate)?.data { + userInfo[Notification.Key.ResponseData] = data + } + + NotificationCenter.default.post( + name: Notification.Name.Task.DidComplete, + object: strongSelf, + userInfo: userInfo + ) + + strongSelf[task] = nil + } + + guard let request = self[task], let sessionManager = sessionManager else { + completeTask(session, task, error) + return + } + + // Run all validations on the request before checking if an error occurred + request.validations.forEach { $0() } + + // Determine whether an error has occurred + var error: Error? = error + + if request.delegate.error != nil { + error = request.delegate.error + } + + /// If an error occurred and the retrier is set, asynchronously ask the retrier if the request + /// should be retried. Otherwise, complete the task by notifying the task delegate. + if let retrier = retrier, let error = error { + retrier.should(sessionManager, retry: request, with: error) { [weak self] shouldRetry, timeDelay in + guard shouldRetry else { completeTask(session, task, error) ; return } + + DispatchQueue.utility.after(timeDelay) { [weak self] in + guard let strongSelf = self else { return } + + let retrySucceeded = strongSelf.sessionManager?.retry(request) ?? false + + if retrySucceeded, let task = request.task { + strongSelf[task] = request + return + } else { + completeTask(session, task, error) + } + } + } + } else { + completeTask(session, task, error) + } + } +} + +// MARK: - URLSessionDataDelegate + +extension SessionDelegate: URLSessionDataDelegate { + /// Tells the delegate that the data task received the initial reply (headers) from the server. + /// + /// - parameter session: The session containing the data task that received an initial reply. + /// - parameter dataTask: The data task that received an initial reply. + /// - parameter response: A URL response object populated with headers. + /// - parameter completionHandler: A completion handler that your code calls to continue the transfer, passing a + /// constant to indicate whether the transfer should continue as a data task or + /// should become a download task. + open func urlSession( + _ session: URLSession, + dataTask: URLSessionDataTask, + didReceive response: URLResponse, + completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) + { + guard dataTaskDidReceiveResponseWithCompletion == nil else { + dataTaskDidReceiveResponseWithCompletion?(session, dataTask, response, completionHandler) + return + } + + var disposition: URLSession.ResponseDisposition = .allow + + if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse { + disposition = dataTaskDidReceiveResponse(session, dataTask, response) + } + + completionHandler(disposition) + } + + /// Tells the delegate that the data task was changed to a download task. + /// + /// - parameter session: The session containing the task that was replaced by a download task. + /// - parameter dataTask: The data task that was replaced by a download task. + /// - parameter downloadTask: The new download task that replaced the data task. + open func urlSession( + _ session: URLSession, + dataTask: URLSessionDataTask, + didBecome downloadTask: URLSessionDownloadTask) + { + if let dataTaskDidBecomeDownloadTask = dataTaskDidBecomeDownloadTask { + dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask) + } else { + self[downloadTask]?.delegate = DownloadTaskDelegate(task: downloadTask) + } + } + + /// Tells the delegate that the data task has received some of the expected data. + /// + /// - parameter session: The session containing the data task that provided data. + /// - parameter dataTask: The data task that provided data. + /// - parameter data: A data object containing the transferred data. + open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { + if let dataTaskDidReceiveData = dataTaskDidReceiveData { + dataTaskDidReceiveData(session, dataTask, data) + } else if let delegate = self[dataTask]?.delegate as? DataTaskDelegate { + delegate.urlSession(session, dataTask: dataTask, didReceive: data) + } + } + + /// Asks the delegate whether the data (or upload) task should store the response in the cache. + /// + /// - parameter session: The session containing the data (or upload) task. + /// - parameter dataTask: The data (or upload) task. + /// - parameter proposedResponse: The default caching behavior. This behavior is determined based on the current + /// caching policy and the values of certain received headers, such as the Pragma + /// and Cache-Control headers. + /// - parameter completionHandler: A block that your handler must call, providing either the original proposed + /// response, a modified version of that response, or NULL to prevent caching the + /// response. If your delegate implements this method, it must call this completion + /// handler; otherwise, your app leaks memory. + open func urlSession( + _ session: URLSession, + dataTask: URLSessionDataTask, + willCacheResponse proposedResponse: CachedURLResponse, + completionHandler: @escaping (CachedURLResponse?) -> Void) + { + guard dataTaskWillCacheResponseWithCompletion == nil else { + dataTaskWillCacheResponseWithCompletion?(session, dataTask, proposedResponse, completionHandler) + return + } + + if let dataTaskWillCacheResponse = dataTaskWillCacheResponse { + completionHandler(dataTaskWillCacheResponse(session, dataTask, proposedResponse)) + } else if let delegate = self[dataTask]?.delegate as? DataTaskDelegate { + delegate.urlSession( + session, + dataTask: dataTask, + willCacheResponse: proposedResponse, + completionHandler: completionHandler + ) + } else { + completionHandler(proposedResponse) + } + } +} + +// MARK: - URLSessionDownloadDelegate + +extension SessionDelegate: URLSessionDownloadDelegate { + /// Tells the delegate that a download task has finished downloading. + /// + /// - parameter session: The session containing the download task that finished. + /// - parameter downloadTask: The download task that finished. + /// - parameter location: A file URL for the temporary file. Because the file is temporary, you must either + /// open the file for reading or move it to a permanent location in your app’s sandbox + /// container directory before returning from this delegate method. + open func urlSession( + _ session: URLSession, + downloadTask: URLSessionDownloadTask, + didFinishDownloadingTo location: URL) + { + if let downloadTaskDidFinishDownloadingToURL = downloadTaskDidFinishDownloadingToURL { + downloadTaskDidFinishDownloadingToURL(session, downloadTask, location) + } else if let delegate = self[downloadTask]?.delegate as? DownloadTaskDelegate { + delegate.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location) + } + } + + /// Periodically informs the delegate about the download’s progress. + /// + /// - parameter session: The session containing the download task. + /// - parameter downloadTask: The download task. + /// - parameter bytesWritten: The number of bytes transferred since the last time this delegate + /// method was called. + /// - parameter totalBytesWritten: The total number of bytes transferred so far. + /// - parameter totalBytesExpectedToWrite: The expected length of the file, as provided by the Content-Length + /// header. If this header was not provided, the value is + /// `NSURLSessionTransferSizeUnknown`. + open func urlSession( + _ session: URLSession, + downloadTask: URLSessionDownloadTask, + didWriteData bytesWritten: Int64, + totalBytesWritten: Int64, + totalBytesExpectedToWrite: Int64) + { + if let downloadTaskDidWriteData = downloadTaskDidWriteData { + downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) + } else if let delegate = self[downloadTask]?.delegate as? DownloadTaskDelegate { + delegate.urlSession( + session, + downloadTask: downloadTask, + didWriteData: bytesWritten, + totalBytesWritten: totalBytesWritten, + totalBytesExpectedToWrite: totalBytesExpectedToWrite + ) + } + } + + /// Tells the delegate that the download task has resumed downloading. + /// + /// - parameter session: The session containing the download task that finished. + /// - parameter downloadTask: The download task that resumed. See explanation in the discussion. + /// - parameter fileOffset: If the file's cache policy or last modified date prevents reuse of the + /// existing content, then this value is zero. Otherwise, this value is an + /// integer representing the number of bytes on disk that do not need to be + /// retrieved again. + /// - parameter expectedTotalBytes: The expected length of the file, as provided by the Content-Length header. + /// If this header was not provided, the value is NSURLSessionTransferSizeUnknown. + open func urlSession( + _ session: URLSession, + downloadTask: URLSessionDownloadTask, + didResumeAtOffset fileOffset: Int64, + expectedTotalBytes: Int64) + { + if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset { + downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes) + } else if let delegate = self[downloadTask]?.delegate as? DownloadTaskDelegate { + delegate.urlSession( + session, + downloadTask: downloadTask, + didResumeAtOffset: fileOffset, + expectedTotalBytes: expectedTotalBytes + ) + } + } +} + +// MARK: - URLSessionStreamDelegate + +#if !os(watchOS) + +@available(iOS 9.0, macOS 10.11, tvOS 9.0, *) +extension SessionDelegate: URLSessionStreamDelegate { + /// Tells the delegate that the read side of the connection has been closed. + /// + /// - parameter session: The session. + /// - parameter streamTask: The stream task. + open func urlSession(_ session: URLSession, readClosedFor streamTask: URLSessionStreamTask) { + streamTaskReadClosed?(session, streamTask) + } + + /// Tells the delegate that the write side of the connection has been closed. + /// + /// - parameter session: The session. + /// - parameter streamTask: The stream task. + open func urlSession(_ session: URLSession, writeClosedFor streamTask: URLSessionStreamTask) { + streamTaskWriteClosed?(session, streamTask) + } + + /// Tells the delegate that the system has determined that a better route to the host is available. + /// + /// - parameter session: The session. + /// - parameter streamTask: The stream task. + open func urlSession(_ session: URLSession, betterRouteDiscoveredFor streamTask: URLSessionStreamTask) { + streamTaskBetterRouteDiscovered?(session, streamTask) + } + + /// Tells the delegate that the stream task has been completed and provides the unopened stream objects. + /// + /// - parameter session: The session. + /// - parameter streamTask: The stream task. + /// - parameter inputStream: The new input stream. + /// - parameter outputStream: The new output stream. + open func urlSession( + _ session: URLSession, + streamTask: URLSessionStreamTask, + didBecome inputStream: InputStream, + outputStream: OutputStream) + { + streamTaskDidBecomeInputAndOutputStreams?(session, streamTask, inputStream, outputStream) + } +} + +#endif diff --git a/Pods/Alamofire/Source/SessionManager.swift b/Pods/Alamofire/Source/SessionManager.swift new file mode 100644 index 0000000..02c36a7 --- /dev/null +++ b/Pods/Alamofire/Source/SessionManager.swift @@ -0,0 +1,899 @@ +// +// SessionManager.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// Responsible for creating and managing `Request` objects, as well as their underlying `NSURLSession`. +open class SessionManager { + + // MARK: - Helper Types + + /// Defines whether the `MultipartFormData` encoding was successful and contains result of the encoding as + /// associated values. + /// + /// - Success: Represents a successful `MultipartFormData` encoding and contains the new `UploadRequest` along with + /// streaming information. + /// - Failure: Used to represent a failure in the `MultipartFormData` encoding and also contains the encoding + /// error. + public enum MultipartFormDataEncodingResult { + case success(request: UploadRequest, streamingFromDisk: Bool, streamFileURL: URL?) + case failure(Error) + } + + // MARK: - Properties + + /// A default instance of `SessionManager`, used by top-level Alamofire request methods, and suitable for use + /// directly for any ad hoc requests. + public static let `default`: SessionManager = { + let configuration = URLSessionConfiguration.default + configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders + + return SessionManager(configuration: configuration) + }() + + /// Creates default values for the "Accept-Encoding", "Accept-Language" and "User-Agent" headers. + public static let defaultHTTPHeaders: HTTPHeaders = { + // Accept-Encoding HTTP Header; see https://tools.ietf.org/html/rfc7230#section-4.2.3 + let acceptEncoding: String = "gzip;q=1.0, compress;q=0.5" + + // Accept-Language HTTP Header; see https://tools.ietf.org/html/rfc7231#section-5.3.5 + let acceptLanguage = Locale.preferredLanguages.prefix(6).enumerated().map { index, languageCode in + let quality = 1.0 - (Double(index) * 0.1) + return "\(languageCode);q=\(quality)" + }.joined(separator: ", ") + + // User-Agent Header; see https://tools.ietf.org/html/rfc7231#section-5.5.3 + // Example: `iOS Example/1.0 (org.alamofire.iOS-Example; build:1; iOS 10.0.0) Alamofire/4.0.0` + let userAgent: String = { + if let info = Bundle.main.infoDictionary { + let executable = info[kCFBundleExecutableKey as String] as? String ?? "Unknown" + let bundle = info[kCFBundleIdentifierKey as String] as? String ?? "Unknown" + let appVersion = info["CFBundleShortVersionString"] as? String ?? "Unknown" + let appBuild = info[kCFBundleVersionKey as String] as? String ?? "Unknown" + + let osNameVersion: String = { + let version = ProcessInfo.processInfo.operatingSystemVersion + let versionString = "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)" + + let osName: String = { + #if os(iOS) + return "iOS" + #elseif os(watchOS) + return "watchOS" + #elseif os(tvOS) + return "tvOS" + #elseif os(macOS) + return "OS X" + #elseif os(Linux) + return "Linux" + #else + return "Unknown" + #endif + }() + + return "\(osName) \(versionString)" + }() + + let alamofireVersion: String = { + guard + let afInfo = Bundle(for: SessionManager.self).infoDictionary, + let build = afInfo["CFBundleShortVersionString"] + else { return "Unknown" } + + return "Alamofire/\(build)" + }() + + return "\(executable)/\(appVersion) (\(bundle); build:\(appBuild); \(osNameVersion)) \(alamofireVersion)" + } + + return "Alamofire" + }() + + return [ + "Accept-Encoding": acceptEncoding, + "Accept-Language": acceptLanguage, + "User-Agent": userAgent + ] + }() + + /// Default memory threshold used when encoding `MultipartFormData` in bytes. + public static let multipartFormDataEncodingMemoryThreshold: UInt64 = 10_000_000 + + /// The underlying session. + public let session: URLSession + + /// The session delegate handling all the task and session delegate callbacks. + public let delegate: SessionDelegate + + /// Whether to start requests immediately after being constructed. `true` by default. + open var startRequestsImmediately: Bool = true + + /// The request adapter called each time a new request is created. + open var adapter: RequestAdapter? + + /// The request retrier called each time a request encounters an error to determine whether to retry the request. + open var retrier: RequestRetrier? { + get { return delegate.retrier } + set { delegate.retrier = newValue } + } + + /// The background completion handler closure provided by the UIApplicationDelegate + /// `application:handleEventsForBackgroundURLSession:completionHandler:` method. By setting the background + /// completion handler, the SessionDelegate `sessionDidFinishEventsForBackgroundURLSession` closure implementation + /// will automatically call the handler. + /// + /// If you need to handle your own events before the handler is called, then you need to override the + /// SessionDelegate `sessionDidFinishEventsForBackgroundURLSession` and manually call the handler when finished. + /// + /// `nil` by default. + open var backgroundCompletionHandler: (() -> Void)? + + let queue = DispatchQueue(label: "org.alamofire.session-manager." + UUID().uuidString) + + // MARK: - Lifecycle + + /// Creates an instance with the specified `configuration`, `delegate` and `serverTrustPolicyManager`. + /// + /// - parameter configuration: The configuration used to construct the managed session. + /// `URLSessionConfiguration.default` by default. + /// - parameter delegate: The delegate used when initializing the session. `SessionDelegate()` by + /// default. + /// - parameter serverTrustPolicyManager: The server trust policy manager to use for evaluating all server trust + /// challenges. `nil` by default. + /// + /// - returns: The new `SessionManager` instance. + public init( + configuration: URLSessionConfiguration = URLSessionConfiguration.default, + delegate: SessionDelegate = SessionDelegate(), + serverTrustPolicyManager: ServerTrustPolicyManager? = nil) + { + self.delegate = delegate + self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil) + + commonInit(serverTrustPolicyManager: serverTrustPolicyManager) + } + + /// Creates an instance with the specified `session`, `delegate` and `serverTrustPolicyManager`. + /// + /// - parameter session: The URL session. + /// - parameter delegate: The delegate of the URL session. Must equal the URL session's delegate. + /// - parameter serverTrustPolicyManager: The server trust policy manager to use for evaluating all server trust + /// challenges. `nil` by default. + /// + /// - returns: The new `SessionManager` instance if the URL session's delegate matches; `nil` otherwise. + public init?( + session: URLSession, + delegate: SessionDelegate, + serverTrustPolicyManager: ServerTrustPolicyManager? = nil) + { + guard delegate === session.delegate else { return nil } + + self.delegate = delegate + self.session = session + + commonInit(serverTrustPolicyManager: serverTrustPolicyManager) + } + + private func commonInit(serverTrustPolicyManager: ServerTrustPolicyManager?) { + session.serverTrustPolicyManager = serverTrustPolicyManager + + delegate.sessionManager = self + + delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in + guard let strongSelf = self else { return } + DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() } + } + } + + deinit { + session.invalidateAndCancel() + } + + // MARK: - Data Request + + /// Creates a `DataRequest` to retrieve the contents of the specified `url`, `method`, `parameters`, `encoding` + /// and `headers`. + /// + /// - parameter url: The URL. + /// - parameter method: The HTTP method. `.get` by default. + /// - parameter parameters: The parameters. `nil` by default. + /// - parameter encoding: The parameter encoding. `URLEncoding.default` by default. + /// - parameter headers: The HTTP headers. `nil` by default. + /// + /// - returns: The created `DataRequest`. + @discardableResult + open func request( + _ url: URLConvertible, + method: HTTPMethod = .get, + parameters: Parameters? = nil, + encoding: ParameterEncoding = URLEncoding.default, + headers: HTTPHeaders? = nil) + -> DataRequest + { + var originalRequest: URLRequest? + + do { + originalRequest = try URLRequest(url: url, method: method, headers: headers) + let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters) + return request(encodedURLRequest) + } catch { + return request(originalRequest, failedWith: error) + } + } + + /// Creates a `DataRequest` to retrieve the contents of a URL based on the specified `urlRequest`. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter urlRequest: The URL request. + /// + /// - returns: The created `DataRequest`. + @discardableResult + open func request(_ urlRequest: URLRequestConvertible) -> DataRequest { + var originalRequest: URLRequest? + + do { + originalRequest = try urlRequest.asURLRequest() + let originalTask = DataRequest.Requestable(urlRequest: originalRequest!) + + let task = try originalTask.task(session: session, adapter: adapter, queue: queue) + let request = DataRequest(session: session, requestTask: .data(originalTask, task)) + + delegate[task] = request + + if startRequestsImmediately { request.resume() } + + return request + } catch { + return request(originalRequest, failedWith: error) + } + } + + // MARK: Private - Request Implementation + + private func request(_ urlRequest: URLRequest?, failedWith error: Error) -> DataRequest { + var requestTask: Request.RequestTask = .data(nil, nil) + + if let urlRequest = urlRequest { + let originalTask = DataRequest.Requestable(urlRequest: urlRequest) + requestTask = .data(originalTask, nil) + } + + let underlyingError = error.underlyingAdaptError ?? error + let request = DataRequest(session: session, requestTask: requestTask, error: underlyingError) + + if let retrier = retrier, error is AdaptError { + allowRetrier(retrier, toRetry: request, with: underlyingError) + } else { + if startRequestsImmediately { request.resume() } + } + + return request + } + + // MARK: - Download Request + + // MARK: URL Request + + /// Creates a `DownloadRequest` to retrieve the contents the specified `url`, `method`, `parameters`, `encoding`, + /// `headers` and save them to the `destination`. + /// + /// If `destination` is not specified, the contents will remain in the temporary location determined by the + /// underlying URL session. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter url: The URL. + /// - parameter method: The HTTP method. `.get` by default. + /// - parameter parameters: The parameters. `nil` by default. + /// - parameter encoding: The parameter encoding. `URLEncoding.default` by default. + /// - parameter headers: The HTTP headers. `nil` by default. + /// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default. + /// + /// - returns: The created `DownloadRequest`. + @discardableResult + open func download( + _ url: URLConvertible, + method: HTTPMethod = .get, + parameters: Parameters? = nil, + encoding: ParameterEncoding = URLEncoding.default, + headers: HTTPHeaders? = nil, + to destination: DownloadRequest.DownloadFileDestination? = nil) + -> DownloadRequest + { + do { + let urlRequest = try URLRequest(url: url, method: method, headers: headers) + let encodedURLRequest = try encoding.encode(urlRequest, with: parameters) + return download(encodedURLRequest, to: destination) + } catch { + return download(nil, to: destination, failedWith: error) + } + } + + /// Creates a `DownloadRequest` to retrieve the contents of a URL based on the specified `urlRequest` and save + /// them to the `destination`. + /// + /// If `destination` is not specified, the contents will remain in the temporary location determined by the + /// underlying URL session. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter urlRequest: The URL request + /// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default. + /// + /// - returns: The created `DownloadRequest`. + @discardableResult + open func download( + _ urlRequest: URLRequestConvertible, + to destination: DownloadRequest.DownloadFileDestination? = nil) + -> DownloadRequest + { + do { + let urlRequest = try urlRequest.asURLRequest() + return download(.request(urlRequest), to: destination) + } catch { + return download(nil, to: destination, failedWith: error) + } + } + + // MARK: Resume Data + + /// Creates a `DownloadRequest` from the `resumeData` produced from a previous request cancellation to retrieve + /// the contents of the original request and save them to the `destination`. + /// + /// If `destination` is not specified, the contents will remain in the temporary location determined by the + /// underlying URL session. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// On the latest release of all the Apple platforms (iOS 10, macOS 10.12, tvOS 10, watchOS 3), `resumeData` is broken + /// on background URL session configurations. There's an underlying bug in the `resumeData` generation logic where the + /// data is written incorrectly and will always fail to resume the download. For more information about the bug and + /// possible workarounds, please refer to the following Stack Overflow post: + /// + /// - http://stackoverflow.com/a/39347461/1342462 + /// + /// - parameter resumeData: The resume data. This is an opaque data blob produced by `URLSessionDownloadTask` + /// when a task is cancelled. See `URLSession -downloadTask(withResumeData:)` for + /// additional information. + /// - parameter destination: The closure used to determine the destination of the downloaded file. `nil` by default. + /// + /// - returns: The created `DownloadRequest`. + @discardableResult + open func download( + resumingWith resumeData: Data, + to destination: DownloadRequest.DownloadFileDestination? = nil) + -> DownloadRequest + { + return download(.resumeData(resumeData), to: destination) + } + + // MARK: Private - Download Implementation + + private func download( + _ downloadable: DownloadRequest.Downloadable, + to destination: DownloadRequest.DownloadFileDestination?) + -> DownloadRequest + { + do { + let task = try downloadable.task(session: session, adapter: adapter, queue: queue) + let download = DownloadRequest(session: session, requestTask: .download(downloadable, task)) + + download.downloadDelegate.destination = destination + + delegate[task] = download + + if startRequestsImmediately { download.resume() } + + return download + } catch { + return download(downloadable, to: destination, failedWith: error) + } + } + + private func download( + _ downloadable: DownloadRequest.Downloadable?, + to destination: DownloadRequest.DownloadFileDestination?, + failedWith error: Error) + -> DownloadRequest + { + var downloadTask: Request.RequestTask = .download(nil, nil) + + if let downloadable = downloadable { + downloadTask = .download(downloadable, nil) + } + + let underlyingError = error.underlyingAdaptError ?? error + + let download = DownloadRequest(session: session, requestTask: downloadTask, error: underlyingError) + download.downloadDelegate.destination = destination + + if let retrier = retrier, error is AdaptError { + allowRetrier(retrier, toRetry: download, with: underlyingError) + } else { + if startRequestsImmediately { download.resume() } + } + + return download + } + + // MARK: - Upload Request + + // MARK: File + + /// Creates an `UploadRequest` from the specified `url`, `method` and `headers` for uploading the `file`. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter file: The file to upload. + /// - parameter url: The URL. + /// - parameter method: The HTTP method. `.post` by default. + /// - parameter headers: The HTTP headers. `nil` by default. + /// + /// - returns: The created `UploadRequest`. + @discardableResult + open func upload( + _ fileURL: URL, + to url: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil) + -> UploadRequest + { + do { + let urlRequest = try URLRequest(url: url, method: method, headers: headers) + return upload(fileURL, with: urlRequest) + } catch { + return upload(nil, failedWith: error) + } + } + + /// Creates a `UploadRequest` from the specified `urlRequest` for uploading the `file`. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter file: The file to upload. + /// - parameter urlRequest: The URL request. + /// + /// - returns: The created `UploadRequest`. + @discardableResult + open func upload(_ fileURL: URL, with urlRequest: URLRequestConvertible) -> UploadRequest { + do { + let urlRequest = try urlRequest.asURLRequest() + return upload(.file(fileURL, urlRequest)) + } catch { + return upload(nil, failedWith: error) + } + } + + // MARK: Data + + /// Creates an `UploadRequest` from the specified `url`, `method` and `headers` for uploading the `data`. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter data: The data to upload. + /// - parameter url: The URL. + /// - parameter method: The HTTP method. `.post` by default. + /// - parameter headers: The HTTP headers. `nil` by default. + /// + /// - returns: The created `UploadRequest`. + @discardableResult + open func upload( + _ data: Data, + to url: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil) + -> UploadRequest + { + do { + let urlRequest = try URLRequest(url: url, method: method, headers: headers) + return upload(data, with: urlRequest) + } catch { + return upload(nil, failedWith: error) + } + } + + /// Creates an `UploadRequest` from the specified `urlRequest` for uploading the `data`. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter data: The data to upload. + /// - parameter urlRequest: The URL request. + /// + /// - returns: The created `UploadRequest`. + @discardableResult + open func upload(_ data: Data, with urlRequest: URLRequestConvertible) -> UploadRequest { + do { + let urlRequest = try urlRequest.asURLRequest() + return upload(.data(data, urlRequest)) + } catch { + return upload(nil, failedWith: error) + } + } + + // MARK: InputStream + + /// Creates an `UploadRequest` from the specified `url`, `method` and `headers` for uploading the `stream`. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter stream: The stream to upload. + /// - parameter url: The URL. + /// - parameter method: The HTTP method. `.post` by default. + /// - parameter headers: The HTTP headers. `nil` by default. + /// + /// - returns: The created `UploadRequest`. + @discardableResult + open func upload( + _ stream: InputStream, + to url: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil) + -> UploadRequest + { + do { + let urlRequest = try URLRequest(url: url, method: method, headers: headers) + return upload(stream, with: urlRequest) + } catch { + return upload(nil, failedWith: error) + } + } + + /// Creates an `UploadRequest` from the specified `urlRequest` for uploading the `stream`. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter stream: The stream to upload. + /// - parameter urlRequest: The URL request. + /// + /// - returns: The created `UploadRequest`. + @discardableResult + open func upload(_ stream: InputStream, with urlRequest: URLRequestConvertible) -> UploadRequest { + do { + let urlRequest = try urlRequest.asURLRequest() + return upload(.stream(stream, urlRequest)) + } catch { + return upload(nil, failedWith: error) + } + } + + // MARK: MultipartFormData + + /// Encodes `multipartFormData` using `encodingMemoryThreshold` and calls `encodingCompletion` with new + /// `UploadRequest` using the `url`, `method` and `headers`. + /// + /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative + /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most + /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to + /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory + /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be + /// used for larger payloads such as video content. + /// + /// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory + /// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`, + /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk + /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding + /// technique was used. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`. + /// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes. + /// `multipartFormDataEncodingMemoryThreshold` by default. + /// - parameter url: The URL. + /// - parameter method: The HTTP method. `.post` by default. + /// - parameter headers: The HTTP headers. `nil` by default. + /// - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete. + open func upload( + multipartFormData: @escaping (MultipartFormData) -> Void, + usingThreshold encodingMemoryThreshold: UInt64 = SessionManager.multipartFormDataEncodingMemoryThreshold, + to url: URLConvertible, + method: HTTPMethod = .post, + headers: HTTPHeaders? = nil, + queue: DispatchQueue? = nil, + encodingCompletion: ((MultipartFormDataEncodingResult) -> Void)?) + { + do { + let urlRequest = try URLRequest(url: url, method: method, headers: headers) + + return upload( + multipartFormData: multipartFormData, + usingThreshold: encodingMemoryThreshold, + with: urlRequest, + queue: queue, + encodingCompletion: encodingCompletion + ) + } catch { + (queue ?? DispatchQueue.main).async { encodingCompletion?(.failure(error)) } + } + } + + /// Encodes `multipartFormData` using `encodingMemoryThreshold` and calls `encodingCompletion` with new + /// `UploadRequest` using the `urlRequest`. + /// + /// It is important to understand the memory implications of uploading `MultipartFormData`. If the cummulative + /// payload is small, encoding the data in-memory and directly uploading to a server is the by far the most + /// efficient approach. However, if the payload is too large, encoding the data in-memory could cause your app to + /// be terminated. Larger payloads must first be written to disk using input and output streams to keep the memory + /// footprint low, then the data can be uploaded as a stream from the resulting file. Streaming from disk MUST be + /// used for larger payloads such as video content. + /// + /// The `encodingMemoryThreshold` parameter allows Alamofire to automatically determine whether to encode in-memory + /// or stream from disk. If the content length of the `MultipartFormData` is below the `encodingMemoryThreshold`, + /// encoding takes place in-memory. If the content length exceeds the threshold, the data is streamed to disk + /// during the encoding process. Then the result is uploaded as data or as a stream depending on which encoding + /// technique was used. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter multipartFormData: The closure used to append body parts to the `MultipartFormData`. + /// - parameter encodingMemoryThreshold: The encoding memory threshold in bytes. + /// `multipartFormDataEncodingMemoryThreshold` by default. + /// - parameter urlRequest: The URL request. + /// - parameter encodingCompletion: The closure called when the `MultipartFormData` encoding is complete. + open func upload( + multipartFormData: @escaping (MultipartFormData) -> Void, + usingThreshold encodingMemoryThreshold: UInt64 = SessionManager.multipartFormDataEncodingMemoryThreshold, + with urlRequest: URLRequestConvertible, + queue: DispatchQueue? = nil, + encodingCompletion: ((MultipartFormDataEncodingResult) -> Void)?) + { + DispatchQueue.global(qos: .utility).async { + let formData = MultipartFormData() + multipartFormData(formData) + + var tempFileURL: URL? + + do { + var urlRequestWithContentType = try urlRequest.asURLRequest() + urlRequestWithContentType.setValue(formData.contentType, forHTTPHeaderField: "Content-Type") + + let isBackgroundSession = self.session.configuration.identifier != nil + + if formData.contentLength < encodingMemoryThreshold && !isBackgroundSession { + let data = try formData.encode() + + let encodingResult = MultipartFormDataEncodingResult.success( + request: self.upload(data, with: urlRequestWithContentType), + streamingFromDisk: false, + streamFileURL: nil + ) + + (queue ?? DispatchQueue.main).async { encodingCompletion?(encodingResult) } + } else { + let fileManager = FileManager.default + let tempDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory()) + let directoryURL = tempDirectoryURL.appendingPathComponent("org.alamofire.manager/multipart.form.data") + let fileName = UUID().uuidString + let fileURL = directoryURL.appendingPathComponent(fileName) + + tempFileURL = fileURL + + var directoryError: Error? + + // Create directory inside serial queue to ensure two threads don't do this in parallel + self.queue.sync { + do { + try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil) + } catch { + directoryError = error + } + } + + if let directoryError = directoryError { throw directoryError } + + try formData.writeEncodedData(to: fileURL) + + let upload = self.upload(fileURL, with: urlRequestWithContentType) + + // Cleanup the temp file once the upload is complete + upload.delegate.queue.addOperation { + do { + try FileManager.default.removeItem(at: fileURL) + } catch { + // No-op + } + } + + (queue ?? DispatchQueue.main).async { + let encodingResult = MultipartFormDataEncodingResult.success( + request: upload, + streamingFromDisk: true, + streamFileURL: fileURL + ) + + encodingCompletion?(encodingResult) + } + } + } catch { + // Cleanup the temp file in the event that the multipart form data encoding failed + if let tempFileURL = tempFileURL { + do { + try FileManager.default.removeItem(at: tempFileURL) + } catch { + // No-op + } + } + + (queue ?? DispatchQueue.main).async { encodingCompletion?(.failure(error)) } + } + } + } + + // MARK: Private - Upload Implementation + + private func upload(_ uploadable: UploadRequest.Uploadable) -> UploadRequest { + do { + let task = try uploadable.task(session: session, adapter: adapter, queue: queue) + let upload = UploadRequest(session: session, requestTask: .upload(uploadable, task)) + + if case let .stream(inputStream, _) = uploadable { + upload.delegate.taskNeedNewBodyStream = { _, _ in inputStream } + } + + delegate[task] = upload + + if startRequestsImmediately { upload.resume() } + + return upload + } catch { + return upload(uploadable, failedWith: error) + } + } + + private func upload(_ uploadable: UploadRequest.Uploadable?, failedWith error: Error) -> UploadRequest { + var uploadTask: Request.RequestTask = .upload(nil, nil) + + if let uploadable = uploadable { + uploadTask = .upload(uploadable, nil) + } + + let underlyingError = error.underlyingAdaptError ?? error + let upload = UploadRequest(session: session, requestTask: uploadTask, error: underlyingError) + + if let retrier = retrier, error is AdaptError { + allowRetrier(retrier, toRetry: upload, with: underlyingError) + } else { + if startRequestsImmediately { upload.resume() } + } + + return upload + } + +#if !os(watchOS) + + // MARK: - Stream Request + + // MARK: Hostname and Port + + /// Creates a `StreamRequest` for bidirectional streaming using the `hostname` and `port`. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter hostName: The hostname of the server to connect to. + /// - parameter port: The port of the server to connect to. + /// + /// - returns: The created `StreamRequest`. + @discardableResult + @available(iOS 9.0, macOS 10.11, tvOS 9.0, *) + open func stream(withHostName hostName: String, port: Int) -> StreamRequest { + return stream(.stream(hostName: hostName, port: port)) + } + + // MARK: NetService + + /// Creates a `StreamRequest` for bidirectional streaming using the `netService`. + /// + /// If `startRequestsImmediately` is `true`, the request will have `resume()` called before being returned. + /// + /// - parameter netService: The net service used to identify the endpoint. + /// + /// - returns: The created `StreamRequest`. + @discardableResult + @available(iOS 9.0, macOS 10.11, tvOS 9.0, *) + open func stream(with netService: NetService) -> StreamRequest { + return stream(.netService(netService)) + } + + // MARK: Private - Stream Implementation + + @available(iOS 9.0, macOS 10.11, tvOS 9.0, *) + private func stream(_ streamable: StreamRequest.Streamable) -> StreamRequest { + do { + let task = try streamable.task(session: session, adapter: adapter, queue: queue) + let request = StreamRequest(session: session, requestTask: .stream(streamable, task)) + + delegate[task] = request + + if startRequestsImmediately { request.resume() } + + return request + } catch { + return stream(failedWith: error) + } + } + + @available(iOS 9.0, macOS 10.11, tvOS 9.0, *) + private func stream(failedWith error: Error) -> StreamRequest { + let stream = StreamRequest(session: session, requestTask: .stream(nil, nil), error: error) + if startRequestsImmediately { stream.resume() } + return stream + } + +#endif + + // MARK: - Internal - Retry Request + + func retry(_ request: Request) -> Bool { + guard let originalTask = request.originalTask else { return false } + + do { + let task = try originalTask.task(session: session, adapter: adapter, queue: queue) + + if let originalTask = request.task { + delegate[originalTask] = nil // removes the old request to avoid endless growth + } + + request.delegate.task = task // resets all task delegate data + + request.retryCount += 1 + request.startTime = CFAbsoluteTimeGetCurrent() + request.endTime = nil + + task.resume() + + return true + } catch { + request.delegate.error = error.underlyingAdaptError ?? error + return false + } + } + + private func allowRetrier(_ retrier: RequestRetrier, toRetry request: Request, with error: Error) { + DispatchQueue.utility.async { [weak self] in + guard let strongSelf = self else { return } + + retrier.should(strongSelf, retry: request, with: error) { shouldRetry, timeDelay in + guard let strongSelf = self else { return } + + guard shouldRetry else { + if strongSelf.startRequestsImmediately { request.resume() } + return + } + + DispatchQueue.utility.after(timeDelay) { + guard let strongSelf = self else { return } + + let retrySucceeded = strongSelf.retry(request) + + if retrySucceeded, let task = request.task { + strongSelf.delegate[task] = request + } else { + if strongSelf.startRequestsImmediately { request.resume() } + } + } + } + } + } +} diff --git a/Pods/Alamofire/Source/TaskDelegate.swift b/Pods/Alamofire/Source/TaskDelegate.swift new file mode 100644 index 0000000..5705737 --- /dev/null +++ b/Pods/Alamofire/Source/TaskDelegate.swift @@ -0,0 +1,466 @@ +// +// TaskDelegate.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// The task delegate is responsible for handling all delegate callbacks for the underlying task as well as +/// executing all operations attached to the serial operation queue upon task completion. +open class TaskDelegate: NSObject { + + // MARK: Properties + + /// The serial operation queue used to execute all operations after the task completes. + public let queue: OperationQueue + + /// The data returned by the server. + public var data: Data? { return nil } + + /// The error generated throughout the lifecyle of the task. + public var error: Error? + + var task: URLSessionTask? { + set { + taskLock.lock(); defer { taskLock.unlock() } + _task = newValue + } + get { + taskLock.lock(); defer { taskLock.unlock() } + return _task + } + } + + var initialResponseTime: CFAbsoluteTime? + var credential: URLCredential? + var metrics: AnyObject? // URLSessionTaskMetrics + + private var _task: URLSessionTask? { + didSet { reset() } + } + + private let taskLock = NSLock() + + // MARK: Lifecycle + + init(task: URLSessionTask?) { + _task = task + + self.queue = { + let operationQueue = OperationQueue() + + operationQueue.maxConcurrentOperationCount = 1 + operationQueue.isSuspended = true + operationQueue.qualityOfService = .utility + + return operationQueue + }() + } + + func reset() { + error = nil + initialResponseTime = nil + } + + // MARK: URLSessionTaskDelegate + + var taskWillPerformHTTPRedirection: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest) -> URLRequest?)? + var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))? + var taskNeedNewBodyStream: ((URLSession, URLSessionTask) -> InputStream?)? + var taskDidCompleteWithError: ((URLSession, URLSessionTask, Error?) -> Void)? + + @objc(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:) + func urlSession( + _ session: URLSession, + task: URLSessionTask, + willPerformHTTPRedirection response: HTTPURLResponse, + newRequest request: URLRequest, + completionHandler: @escaping (URLRequest?) -> Void) + { + var redirectRequest: URLRequest? = request + + if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection { + redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request) + } + + completionHandler(redirectRequest) + } + + @objc(URLSession:task:didReceiveChallenge:completionHandler:) + func urlSession( + _ session: URLSession, + task: URLSessionTask, + didReceive challenge: URLAuthenticationChallenge, + completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) + { + var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling + var credential: URLCredential? + + if let taskDidReceiveChallenge = taskDidReceiveChallenge { + (disposition, credential) = taskDidReceiveChallenge(session, task, challenge) + } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { + let host = challenge.protectionSpace.host + + if + let serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicy(forHost: host), + let serverTrust = challenge.protectionSpace.serverTrust + { + if serverTrustPolicy.evaluate(serverTrust, forHost: host) { + disposition = .useCredential + credential = URLCredential(trust: serverTrust) + } else { + disposition = .cancelAuthenticationChallenge + } + } + } else { + if challenge.previousFailureCount > 0 { + disposition = .rejectProtectionSpace + } else { + credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace) + + if credential != nil { + disposition = .useCredential + } + } + } + + completionHandler(disposition, credential) + } + + @objc(URLSession:task:needNewBodyStream:) + func urlSession( + _ session: URLSession, + task: URLSessionTask, + needNewBodyStream completionHandler: @escaping (InputStream?) -> Void) + { + var bodyStream: InputStream? + + if let taskNeedNewBodyStream = taskNeedNewBodyStream { + bodyStream = taskNeedNewBodyStream(session, task) + } + + completionHandler(bodyStream) + } + + @objc(URLSession:task:didCompleteWithError:) + func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { + if let taskDidCompleteWithError = taskDidCompleteWithError { + taskDidCompleteWithError(session, task, error) + } else { + if let error = error { + if self.error == nil { self.error = error } + + if + let downloadDelegate = self as? DownloadTaskDelegate, + let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data + { + downloadDelegate.resumeData = resumeData + } + } + + queue.isSuspended = false + } + } +} + +// MARK: - + +class DataTaskDelegate: TaskDelegate, URLSessionDataDelegate { + + // MARK: Properties + + var dataTask: URLSessionDataTask { return task as! URLSessionDataTask } + + override var data: Data? { + if dataStream != nil { + return nil + } else { + return mutableData + } + } + + var progress: Progress + var progressHandler: (closure: Request.ProgressHandler, queue: DispatchQueue)? + + var dataStream: ((_ data: Data) -> Void)? + + private var totalBytesReceived: Int64 = 0 + private var mutableData: Data + + private var expectedContentLength: Int64? + + // MARK: Lifecycle + + override init(task: URLSessionTask?) { + mutableData = Data() + progress = Progress(totalUnitCount: 0) + + super.init(task: task) + } + + override func reset() { + super.reset() + + progress = Progress(totalUnitCount: 0) + totalBytesReceived = 0 + mutableData = Data() + expectedContentLength = nil + } + + // MARK: URLSessionDataDelegate + + var dataTaskDidReceiveResponse: ((URLSession, URLSessionDataTask, URLResponse) -> URLSession.ResponseDisposition)? + var dataTaskDidBecomeDownloadTask: ((URLSession, URLSessionDataTask, URLSessionDownloadTask) -> Void)? + var dataTaskDidReceiveData: ((URLSession, URLSessionDataTask, Data) -> Void)? + var dataTaskWillCacheResponse: ((URLSession, URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)? + + func urlSession( + _ session: URLSession, + dataTask: URLSessionDataTask, + didReceive response: URLResponse, + completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) + { + var disposition: URLSession.ResponseDisposition = .allow + + expectedContentLength = response.expectedContentLength + + if let dataTaskDidReceiveResponse = dataTaskDidReceiveResponse { + disposition = dataTaskDidReceiveResponse(session, dataTask, response) + } + + completionHandler(disposition) + } + + func urlSession( + _ session: URLSession, + dataTask: URLSessionDataTask, + didBecome downloadTask: URLSessionDownloadTask) + { + dataTaskDidBecomeDownloadTask?(session, dataTask, downloadTask) + } + + func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { + if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() } + + if let dataTaskDidReceiveData = dataTaskDidReceiveData { + dataTaskDidReceiveData(session, dataTask, data) + } else { + if let dataStream = dataStream { + dataStream(data) + } else { + mutableData.append(data) + } + + let bytesReceived = Int64(data.count) + totalBytesReceived += bytesReceived + let totalBytesExpected = dataTask.response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown + + progress.totalUnitCount = totalBytesExpected + progress.completedUnitCount = totalBytesReceived + + if let progressHandler = progressHandler { + progressHandler.queue.async { progressHandler.closure(self.progress) } + } + } + } + + func urlSession( + _ session: URLSession, + dataTask: URLSessionDataTask, + willCacheResponse proposedResponse: CachedURLResponse, + completionHandler: @escaping (CachedURLResponse?) -> Void) + { + var cachedResponse: CachedURLResponse? = proposedResponse + + if let dataTaskWillCacheResponse = dataTaskWillCacheResponse { + cachedResponse = dataTaskWillCacheResponse(session, dataTask, proposedResponse) + } + + completionHandler(cachedResponse) + } +} + +// MARK: - + +class DownloadTaskDelegate: TaskDelegate, URLSessionDownloadDelegate { + + // MARK: Properties + + var downloadTask: URLSessionDownloadTask { return task as! URLSessionDownloadTask } + + var progress: Progress + var progressHandler: (closure: Request.ProgressHandler, queue: DispatchQueue)? + + var resumeData: Data? + override var data: Data? { return resumeData } + + var destination: DownloadRequest.DownloadFileDestination? + + var temporaryURL: URL? + var destinationURL: URL? + + var fileURL: URL? { return destination != nil ? destinationURL : temporaryURL } + + // MARK: Lifecycle + + override init(task: URLSessionTask?) { + progress = Progress(totalUnitCount: 0) + super.init(task: task) + } + + override func reset() { + super.reset() + + progress = Progress(totalUnitCount: 0) + resumeData = nil + } + + // MARK: URLSessionDownloadDelegate + + var downloadTaskDidFinishDownloadingToURL: ((URLSession, URLSessionDownloadTask, URL) -> URL)? + var downloadTaskDidWriteData: ((URLSession, URLSessionDownloadTask, Int64, Int64, Int64) -> Void)? + var downloadTaskDidResumeAtOffset: ((URLSession, URLSessionDownloadTask, Int64, Int64) -> Void)? + + func urlSession( + _ session: URLSession, + downloadTask: URLSessionDownloadTask, + didFinishDownloadingTo location: URL) + { + temporaryURL = location + + guard + let destination = destination, + let response = downloadTask.response as? HTTPURLResponse + else { return } + + let result = destination(location, response) + let destinationURL = result.destinationURL + let options = result.options + + self.destinationURL = destinationURL + + do { + if options.contains(.removePreviousFile), FileManager.default.fileExists(atPath: destinationURL.path) { + try FileManager.default.removeItem(at: destinationURL) + } + + if options.contains(.createIntermediateDirectories) { + let directory = destinationURL.deletingLastPathComponent() + try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true) + } + + try FileManager.default.moveItem(at: location, to: destinationURL) + } catch { + self.error = error + } + } + + func urlSession( + _ session: URLSession, + downloadTask: URLSessionDownloadTask, + didWriteData bytesWritten: Int64, + totalBytesWritten: Int64, + totalBytesExpectedToWrite: Int64) + { + if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() } + + if let downloadTaskDidWriteData = downloadTaskDidWriteData { + downloadTaskDidWriteData( + session, + downloadTask, + bytesWritten, + totalBytesWritten, + totalBytesExpectedToWrite + ) + } else { + progress.totalUnitCount = totalBytesExpectedToWrite + progress.completedUnitCount = totalBytesWritten + + if let progressHandler = progressHandler { + progressHandler.queue.async { progressHandler.closure(self.progress) } + } + } + } + + func urlSession( + _ session: URLSession, + downloadTask: URLSessionDownloadTask, + didResumeAtOffset fileOffset: Int64, + expectedTotalBytes: Int64) + { + if let downloadTaskDidResumeAtOffset = downloadTaskDidResumeAtOffset { + downloadTaskDidResumeAtOffset(session, downloadTask, fileOffset, expectedTotalBytes) + } else { + progress.totalUnitCount = expectedTotalBytes + progress.completedUnitCount = fileOffset + } + } +} + +// MARK: - + +class UploadTaskDelegate: DataTaskDelegate { + + // MARK: Properties + + var uploadTask: URLSessionUploadTask { return task as! URLSessionUploadTask } + + var uploadProgress: Progress + var uploadProgressHandler: (closure: Request.ProgressHandler, queue: DispatchQueue)? + + // MARK: Lifecycle + + override init(task: URLSessionTask?) { + uploadProgress = Progress(totalUnitCount: 0) + super.init(task: task) + } + + override func reset() { + super.reset() + uploadProgress = Progress(totalUnitCount: 0) + } + + // MARK: URLSessionTaskDelegate + + var taskDidSendBodyData: ((URLSession, URLSessionTask, Int64, Int64, Int64) -> Void)? + + func URLSession( + _ session: URLSession, + task: URLSessionTask, + didSendBodyData bytesSent: Int64, + totalBytesSent: Int64, + totalBytesExpectedToSend: Int64) + { + if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() } + + if let taskDidSendBodyData = taskDidSendBodyData { + taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalBytesExpectedToSend) + } else { + uploadProgress.totalUnitCount = totalBytesExpectedToSend + uploadProgress.completedUnitCount = totalBytesSent + + if let uploadProgressHandler = uploadProgressHandler { + uploadProgressHandler.queue.async { uploadProgressHandler.closure(self.uploadProgress) } + } + } + } +} diff --git a/Pods/Alamofire/Source/Timeline.swift b/Pods/Alamofire/Source/Timeline.swift new file mode 100644 index 0000000..596c1bd --- /dev/null +++ b/Pods/Alamofire/Source/Timeline.swift @@ -0,0 +1,136 @@ +// +// Timeline.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// Responsible for computing the timing metrics for the complete lifecycle of a `Request`. +public struct Timeline { + /// The time the request was initialized. + public let requestStartTime: CFAbsoluteTime + + /// The time the first bytes were received from or sent to the server. + public let initialResponseTime: CFAbsoluteTime + + /// The time when the request was completed. + public let requestCompletedTime: CFAbsoluteTime + + /// The time when the response serialization was completed. + public let serializationCompletedTime: CFAbsoluteTime + + /// The time interval in seconds from the time the request started to the initial response from the server. + public let latency: TimeInterval + + /// The time interval in seconds from the time the request started to the time the request completed. + public let requestDuration: TimeInterval + + /// The time interval in seconds from the time the request completed to the time response serialization completed. + public let serializationDuration: TimeInterval + + /// The time interval in seconds from the time the request started to the time response serialization completed. + public let totalDuration: TimeInterval + + /// Creates a new `Timeline` instance with the specified request times. + /// + /// - parameter requestStartTime: The time the request was initialized. Defaults to `0.0`. + /// - parameter initialResponseTime: The time the first bytes were received from or sent to the server. + /// Defaults to `0.0`. + /// - parameter requestCompletedTime: The time when the request was completed. Defaults to `0.0`. + /// - parameter serializationCompletedTime: The time when the response serialization was completed. Defaults + /// to `0.0`. + /// + /// - returns: The new `Timeline` instance. + public init( + requestStartTime: CFAbsoluteTime = 0.0, + initialResponseTime: CFAbsoluteTime = 0.0, + requestCompletedTime: CFAbsoluteTime = 0.0, + serializationCompletedTime: CFAbsoluteTime = 0.0) + { + self.requestStartTime = requestStartTime + self.initialResponseTime = initialResponseTime + self.requestCompletedTime = requestCompletedTime + self.serializationCompletedTime = serializationCompletedTime + + self.latency = initialResponseTime - requestStartTime + self.requestDuration = requestCompletedTime - requestStartTime + self.serializationDuration = serializationCompletedTime - requestCompletedTime + self.totalDuration = serializationCompletedTime - requestStartTime + } +} + +// MARK: - CustomStringConvertible + +extension Timeline: CustomStringConvertible { + /// The textual representation used when written to an output stream, which includes the latency, the request + /// duration and the total duration. + public var description: String { + let latency = String(format: "%.3f", self.latency) + let requestDuration = String(format: "%.3f", self.requestDuration) + let serializationDuration = String(format: "%.3f", self.serializationDuration) + let totalDuration = String(format: "%.3f", self.totalDuration) + + // NOTE: Had to move to string concatenation due to memory leak filed as rdar://26761490. Once memory leak is + // fixed, we should move back to string interpolation by reverting commit 7d4a43b1. + let timings = [ + "\"Latency\": " + latency + " secs", + "\"Request Duration\": " + requestDuration + " secs", + "\"Serialization Duration\": " + serializationDuration + " secs", + "\"Total Duration\": " + totalDuration + " secs" + ] + + return "Timeline: { " + timings.joined(separator: ", ") + " }" + } +} + +// MARK: - CustomDebugStringConvertible + +extension Timeline: CustomDebugStringConvertible { + /// The textual representation used when written to an output stream, which includes the request start time, the + /// initial response time, the request completed time, the serialization completed time, the latency, the request + /// duration and the total duration. + public var debugDescription: String { + let requestStartTime = String(format: "%.3f", self.requestStartTime) + let initialResponseTime = String(format: "%.3f", self.initialResponseTime) + let requestCompletedTime = String(format: "%.3f", self.requestCompletedTime) + let serializationCompletedTime = String(format: "%.3f", self.serializationCompletedTime) + let latency = String(format: "%.3f", self.latency) + let requestDuration = String(format: "%.3f", self.requestDuration) + let serializationDuration = String(format: "%.3f", self.serializationDuration) + let totalDuration = String(format: "%.3f", self.totalDuration) + + // NOTE: Had to move to string concatenation due to memory leak filed as rdar://26761490. Once memory leak is + // fixed, we should move back to string interpolation by reverting commit 7d4a43b1. + let timings = [ + "\"Request Start Time\": " + requestStartTime, + "\"Initial Response Time\": " + initialResponseTime, + "\"Request Completed Time\": " + requestCompletedTime, + "\"Serialization Completed Time\": " + serializationCompletedTime, + "\"Latency\": " + latency + " secs", + "\"Request Duration\": " + requestDuration + " secs", + "\"Serialization Duration\": " + serializationDuration + " secs", + "\"Total Duration\": " + totalDuration + " secs" + ] + + return "Timeline: { " + timings.joined(separator: ", ") + " }" + } +} diff --git a/Pods/Alamofire/Source/Validation.swift b/Pods/Alamofire/Source/Validation.swift new file mode 100644 index 0000000..59e0bbb --- /dev/null +++ b/Pods/Alamofire/Source/Validation.swift @@ -0,0 +1,321 @@ +// +// Validation.swift +// +// Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +extension Request { + + // MARK: Helper Types + + fileprivate typealias ErrorReason = AFError.ResponseValidationFailureReason + + /// Used to represent whether validation was successful or encountered an error resulting in a failure. + /// + /// - success: The validation was successful. + /// - failure: The validation failed encountering the provided error. + public enum ValidationResult { + case success + case failure(Error) + } + + fileprivate struct MIMEType { + let type: String + let subtype: String + + var isWildcard: Bool { return type == "*" && subtype == "*" } + + init?(_ string: String) { + let components: [String] = { + let stripped = string.trimmingCharacters(in: .whitespacesAndNewlines) + + #if swift(>=3.2) + let split = stripped[..<(stripped.range(of: ";")?.lowerBound ?? stripped.endIndex)] + #else + let split = stripped.substring(to: stripped.range(of: ";")?.lowerBound ?? stripped.endIndex) + #endif + + return split.components(separatedBy: "/") + }() + + if let type = components.first, let subtype = components.last { + self.type = type + self.subtype = subtype + } else { + return nil + } + } + + func matches(_ mime: MIMEType) -> Bool { + switch (type, subtype) { + case (mime.type, mime.subtype), (mime.type, "*"), ("*", mime.subtype), ("*", "*"): + return true + default: + return false + } + } + } + + // MARK: Properties + + fileprivate var acceptableStatusCodes: [Int] { return Array(200..<300) } + + fileprivate var acceptableContentTypes: [String] { + if let accept = request?.value(forHTTPHeaderField: "Accept") { + return accept.components(separatedBy: ",") + } + + return ["*/*"] + } + + // MARK: Status Code + + fileprivate func validate( + statusCode acceptableStatusCodes: S, + response: HTTPURLResponse) + -> ValidationResult + where S.Iterator.Element == Int + { + if acceptableStatusCodes.contains(response.statusCode) { + return .success + } else { + let reason: ErrorReason = .unacceptableStatusCode(code: response.statusCode) + return .failure(AFError.responseValidationFailed(reason: reason)) + } + } + + // MARK: Content Type + + fileprivate func validate( + contentType acceptableContentTypes: S, + response: HTTPURLResponse, + data: Data?) + -> ValidationResult + where S.Iterator.Element == String + { + guard let data = data, data.count > 0 else { return .success } + + guard + let responseContentType = response.mimeType, + let responseMIMEType = MIMEType(responseContentType) + else { + for contentType in acceptableContentTypes { + if let mimeType = MIMEType(contentType), mimeType.isWildcard { + return .success + } + } + + let error: AFError = { + let reason: ErrorReason = .missingContentType(acceptableContentTypes: Array(acceptableContentTypes)) + return AFError.responseValidationFailed(reason: reason) + }() + + return .failure(error) + } + + for contentType in acceptableContentTypes { + if let acceptableMIMEType = MIMEType(contentType), acceptableMIMEType.matches(responseMIMEType) { + return .success + } + } + + let error: AFError = { + let reason: ErrorReason = .unacceptableContentType( + acceptableContentTypes: Array(acceptableContentTypes), + responseContentType: responseContentType + ) + + return AFError.responseValidationFailed(reason: reason) + }() + + return .failure(error) + } +} + +// MARK: - + +extension DataRequest { + /// A closure used to validate a request that takes a URL request, a URL response and data, and returns whether the + /// request was valid. + public typealias Validation = (URLRequest?, HTTPURLResponse, Data?) -> ValidationResult + + /// Validates the request, using the specified closure. + /// + /// If validation fails, subsequent calls to response handlers will have an associated error. + /// + /// - parameter validation: A closure to validate the request. + /// + /// - returns: The request. + @discardableResult + public func validate(_ validation: @escaping Validation) -> Self { + let validationExecution: () -> Void = { [unowned self] in + if + let response = self.response, + self.delegate.error == nil, + case let .failure(error) = validation(self.request, response, self.delegate.data) + { + self.delegate.error = error + } + } + + validations.append(validationExecution) + + return self + } + + /// Validates that the response has a status code in the specified sequence. + /// + /// If validation fails, subsequent calls to response handlers will have an associated error. + /// + /// - parameter range: The range of acceptable status codes. + /// + /// - returns: The request. + @discardableResult + public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int { + return validate { [unowned self] _, response, _ in + return self.validate(statusCode: acceptableStatusCodes, response: response) + } + } + + /// Validates that the response has a content type in the specified sequence. + /// + /// If validation fails, subsequent calls to response handlers will have an associated error. + /// + /// - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes. + /// + /// - returns: The request. + @discardableResult + public func validate(contentType acceptableContentTypes: S) -> Self where S.Iterator.Element == String { + return validate { [unowned self] _, response, data in + return self.validate(contentType: acceptableContentTypes, response: response, data: data) + } + } + + /// Validates that the response has a status code in the default acceptable range of 200...299, and that the content + /// type matches any specified in the Accept HTTP header field. + /// + /// If validation fails, subsequent calls to response handlers will have an associated error. + /// + /// - returns: The request. + @discardableResult + public func validate() -> Self { + let contentTypes = { [unowned self] in + self.acceptableContentTypes + } + return validate(statusCode: acceptableStatusCodes).validate(contentType: contentTypes()) + } +} + +// MARK: - + +extension DownloadRequest { + /// A closure used to validate a request that takes a URL request, a URL response, a temporary URL and a + /// destination URL, and returns whether the request was valid. + public typealias Validation = ( + _ request: URLRequest?, + _ response: HTTPURLResponse, + _ temporaryURL: URL?, + _ destinationURL: URL?) + -> ValidationResult + + /// Validates the request, using the specified closure. + /// + /// If validation fails, subsequent calls to response handlers will have an associated error. + /// + /// - parameter validation: A closure to validate the request. + /// + /// - returns: The request. + @discardableResult + public func validate(_ validation: @escaping Validation) -> Self { + let validationExecution: () -> Void = { [unowned self] in + let request = self.request + let temporaryURL = self.downloadDelegate.temporaryURL + let destinationURL = self.downloadDelegate.destinationURL + + if + let response = self.response, + self.delegate.error == nil, + case let .failure(error) = validation(request, response, temporaryURL, destinationURL) + { + self.delegate.error = error + } + } + + validations.append(validationExecution) + + return self + } + + /// Validates that the response has a status code in the specified sequence. + /// + /// If validation fails, subsequent calls to response handlers will have an associated error. + /// + /// - parameter range: The range of acceptable status codes. + /// + /// - returns: The request. + @discardableResult + public func validate(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int { + return validate { [unowned self] _, response, _, _ in + return self.validate(statusCode: acceptableStatusCodes, response: response) + } + } + + /// Validates that the response has a content type in the specified sequence. + /// + /// If validation fails, subsequent calls to response handlers will have an associated error. + /// + /// - parameter contentType: The acceptable content types, which may specify wildcard types and/or subtypes. + /// + /// - returns: The request. + @discardableResult + public func validate(contentType acceptableContentTypes: S) -> Self where S.Iterator.Element == String { + return validate { [unowned self] _, response, _, _ in + let fileURL = self.downloadDelegate.fileURL + + guard let validFileURL = fileURL else { + return .failure(AFError.responseValidationFailed(reason: .dataFileNil)) + } + + do { + let data = try Data(contentsOf: validFileURL) + return self.validate(contentType: acceptableContentTypes, response: response, data: data) + } catch { + return .failure(AFError.responseValidationFailed(reason: .dataFileReadFailed(at: validFileURL))) + } + } + } + + /// Validates that the response has a status code in the default acceptable range of 200...299, and that the content + /// type matches any specified in the Accept HTTP header field. + /// + /// If validation fails, subsequent calls to response handlers will have an associated error. + /// + /// - returns: The request. + @discardableResult + public func validate() -> Self { + let contentTypes = { [unowned self] in + self.acceptableContentTypes + } + return validate(statusCode: acceptableStatusCodes).validate(contentType: contentTypes()) + } +} diff --git a/Pods/AlamofireObjectMapper/AlamofireObjectMapper/AlamofireObjectMapper.swift b/Pods/AlamofireObjectMapper/AlamofireObjectMapper/AlamofireObjectMapper.swift new file mode 100644 index 0000000..b181e84 --- /dev/null +++ b/Pods/AlamofireObjectMapper/AlamofireObjectMapper/AlamofireObjectMapper.swift @@ -0,0 +1,205 @@ +// +// Request.swift +// AlamofireObjectMapper +// +// Created by Tristan Himmelman on 2015-04-30. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2015 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation +import Alamofire +import ObjectMapper + +extension DataRequest { + + enum ErrorCode: Int { + case noData = 1 + case dataSerializationFailed = 2 + } + + internal static func newError(_ code: ErrorCode, failureReason: String) -> NSError { + let errorDomain = "com.alamofireobjectmapper.error" + + let userInfo = [NSLocalizedFailureReasonErrorKey: failureReason] + let returnError = NSError(domain: errorDomain, code: code.rawValue, userInfo: userInfo) + + return returnError + } + + /// Utility function for checking for errors in response + internal static func checkResponseForError(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) -> Error? { + if let error = error { + return error + } + guard let _ = data else { + let failureReason = "Data could not be serialized. Input data was nil." + let error = newError(.noData, failureReason: failureReason) + return error + } + return nil + } + + /// Utility function for extracting JSON from response + internal static func processResponse(request: URLRequest?, response: HTTPURLResponse?, data: Data?, keyPath: String?) -> Any? { + let jsonResponseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments) + let result = jsonResponseSerializer.serializeResponse(request, response, data, nil) + + let JSON: Any? + if let keyPath = keyPath , keyPath.isEmpty == false { + JSON = (result.value as AnyObject?)?.value(forKeyPath: keyPath) + } else { + JSON = result.value + } + + return JSON + } + + /// BaseMappable Object Serializer + public static func ObjectMapperSerializer(_ keyPath: String?, mapToObject object: T? = nil, context: MapContext? = nil) -> DataResponseSerializer { + return DataResponseSerializer { request, response, data, error in + if let error = checkResponseForError(request: request, response: response, data: data, error: error){ + return .failure(error) + } + + let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath) + + if let object = object { + _ = Mapper(context: context, shouldIncludeNilValues: false).map(JSONObject: JSONObject, toObject: object) + return .success(object) + } else if let parsedObject = Mapper(context: context, shouldIncludeNilValues: false).map(JSONObject: JSONObject){ + return .success(parsedObject) + } + + let failureReason = "ObjectMapper failed to serialize response." + let error = newError(.dataSerializationFailed, failureReason: failureReason) + return .failure(error) + } + } + + /// ImmutableMappable Array Serializer + public static func ObjectMapperImmutableSerializer(_ keyPath: String?, context: MapContext? = nil) -> DataResponseSerializer { + return DataResponseSerializer { request, response, data, error in + if let error = checkResponseForError(request: request, response: response, data: data, error: error){ + return .failure(error) + } + + let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath) + + if let JSONObject = JSONObject, + let parsedObject = (try? Mapper(context: context, shouldIncludeNilValues: false).map(JSONObject: JSONObject)){ + return .success(parsedObject) + } + + let failureReason = "ObjectMapper failed to serialize response." + let error = newError(.dataSerializationFailed, failureReason: failureReason) + return .failure(error) + } + } + + /** + Adds a handler to be called once the request has finished. + + - parameter queue: The queue on which the completion handler is dispatched. + - parameter keyPath: The key path where object mapping should be performed + - parameter object: An object to perform the mapping on to + - parameter completionHandler: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper. + + - returns: The request. + */ + @discardableResult + public func responseObject(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse) -> Void) -> Self { + return response(queue: queue, responseSerializer: DataRequest.ObjectMapperSerializer(keyPath, mapToObject: object, context: context), completionHandler: completionHandler) + } + + @discardableResult + public func responseObject(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse) -> Void) -> Self { + return response(queue: queue, responseSerializer: DataRequest.ObjectMapperImmutableSerializer(keyPath, context: context), completionHandler: completionHandler) + } + + /// BaseMappable Array Serializer + public static func ObjectMapperArraySerializer(_ keyPath: String?, context: MapContext? = nil) -> DataResponseSerializer<[T]> { + return DataResponseSerializer { request, response, data, error in + if let error = checkResponseForError(request: request, response: response, data: data, error: error){ + return .failure(error) + } + + let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath) + + if let parsedObject = Mapper(context: context, shouldIncludeNilValues: false).mapArray(JSONObject: JSONObject){ + return .success(parsedObject) + } + + let failureReason = "ObjectMapper failed to serialize response." + let error = newError(.dataSerializationFailed, failureReason: failureReason) + return .failure(error) + } + } + + /// ImmutableMappable Array Serializer + public static func ObjectMapperImmutableArraySerializer(_ keyPath: String?, context: MapContext? = nil) -> DataResponseSerializer<[T]> { + return DataResponseSerializer { request, response, data, error in + if let error = checkResponseForError(request: request, response: response, data: data, error: error){ + return .failure(error) + } + + if let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath){ + + if let parsedObject = try? Mapper(context: context, shouldIncludeNilValues: false).mapArray(JSONObject: JSONObject){ + return .success(parsedObject) + } + } + + let failureReason = "ObjectMapper failed to serialize response." + let error = newError(.dataSerializationFailed, failureReason: failureReason) + return .failure(error) + } + } + + /** + Adds a handler to be called once the request has finished. T: BaseMappable + + - parameter queue: The queue on which the completion handler is dispatched. + - parameter keyPath: The key path where object mapping should be performed + - parameter completionHandler: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper. + + - returns: The request. + */ + @discardableResult + public func responseArray(queue: DispatchQueue? = nil, keyPath: String? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<[T]>) -> Void) -> Self { + return response(queue: queue, responseSerializer: DataRequest.ObjectMapperArraySerializer(keyPath, context: context), completionHandler: completionHandler) + } + + /** + Adds a handler to be called once the request has finished. T: ImmutableMappable + + - parameter queue: The queue on which the completion handler is dispatched. + - parameter keyPath: The key path where object mapping should be performed + - parameter completionHandler: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper. + + - returns: The request. + */ + @discardableResult + public func responseArray(queue: DispatchQueue? = nil, keyPath: String? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<[T]>) -> Void) -> Self { + return response(queue: queue, responseSerializer: DataRequest.ObjectMapperImmutableArraySerializer(keyPath, context: context), completionHandler: completionHandler) + } +} diff --git a/Pods/AlamofireObjectMapper/LICENSE b/Pods/AlamofireObjectMapper/LICENSE new file mode 100644 index 0000000..cee2d0c --- /dev/null +++ b/Pods/AlamofireObjectMapper/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Tristan Himmelman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Pods/AlamofireObjectMapper/README.md b/Pods/AlamofireObjectMapper/README.md new file mode 100644 index 0000000..55c3ff9 --- /dev/null +++ b/Pods/AlamofireObjectMapper/README.md @@ -0,0 +1,193 @@ +AlamofireObjectMapper +============ +[![Build Status](https://travis-ci.org/tristanhimmelman/AlamofireObjectMapper.svg?branch=master)](https://travis-ci.org/tristanhimmelman/AlamofireObjectMapper) +[![CocoaPods](https://img.shields.io/cocoapods/v/AlamofireObjectMapper.svg)](https://github.com/tristanhimmelman/AlamofireObjectMapper) +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) + + +An extension to [Alamofire](https://github.com/Alamofire/Alamofire) which automatically converts JSON response data into swift objects using [ObjectMapper](https://github.com/Hearst-DD/ObjectMapper/). + +# Usage + +Given a URL which returns weather data in the following form: +``` +{ + "location": "Toronto, Canada", + "three_day_forecast": [ + { + "conditions": "Partly cloudy", + "day" : "Monday", + "temperature": 20 + }, + { + "conditions": "Showers", + "day" : "Tuesday", + "temperature": 22 + }, + { + "conditions": "Sunny", + "day" : "Wednesday", + "temperature": 28 + } + ] +} +``` + +You can use the extension as the follows: +```swift +import AlamofireObjectMapper + +let URL = "https://raw.githubusercontent.com/tristanhimmelman/AlamofireObjectMapper/d8bb95982be8a11a2308e779bb9a9707ebe42ede/sample_json" +Alamofire.request(URL).responseObject { (response: DataResponse) in + + let weatherResponse = response.result.value + print(weatherResponse?.location) + + if let threeDayForecast = weatherResponse?.threeDayForecast { + for forecast in threeDayForecast { + print(forecast.day) + print(forecast.temperature) + } + } +} +``` + +The `WeatherResponse` object in the completion handler is a custom object which you define. The only requirement is that the object must conform to [ObjectMapper's](https://github.com/Hearst-DD/ObjectMapper/) `Mappable` protocol. In the above example, the `WeatherResponse` object looks like the following: + +```swift +import ObjectMapper + +class WeatherResponse: Mappable { + var location: String? + var threeDayForecast: [Forecast]? + + required init?(map: Map){ + + } + + func mapping(map: Map) { + location <- map["location"] + threeDayForecast <- map["three_day_forecast"] + } +} + +class Forecast: Mappable { + var day: String? + var temperature: Int? + var conditions: String? + + required init?(map: Map){ + + } + + func mapping(map: Map) { + day <- map["day"] + temperature <- map["temperature"] + conditions <- map["conditions"] + } +} +``` + +The extension uses Generics to allow you to create your own custom response objects. Below is the `responseObject` function definition. Just replace `T` in the completionHandler with your custom response object and the extension handles the rest: +```swift +public func responseObject(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse) -> Void) -> Self +``` +The `responseObject` function has 4 optional parameters and a required completionHandler: +- `queue`: The queue on which the completion handler is dispatched. +- `keyPath`: The key path of the JSON where object mapping should be performed. +- `mapToObject`: An object to perform the mapping on to. +- `context`: A [context object](https://github.com/Hearst-DD/ObjectMapper/#mapping-context) that is passed to the mapping function. +- `completionHandler`: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper. + +### Easy Mapping of Nested Objects + +AlamofireObjectMapper supports dot notation within keys for easy mapping of nested objects. Given the following JSON String: +```json +"distance" : { + "text" : "102 ft", + "value" : 31 +} +``` +You can access the nested objects as follows: +```swift +func mapping(map: Map) { + distance <- map["distance.value"] +} +``` +[See complete documentation](https://github.com/Hearst-DD/ObjectMapper#easy-mapping-of-nested-objects) + +### KeyPath + +The `keyPath` variable is used to drill down into a JSON response and only map the data found at that `keyPath`. It supports nested values such as `data.weather` to drill down several levels in a JSON response. +```swift +let URL = "https://raw.githubusercontent.com/tristanhimmelman/AlamofireObjectMapper/2ee8f34d21e8febfdefb2b3a403f18a43818d70a/sample_keypath_json" +let expectation = expectationWithDescription("\(URL)") + +Alamofire.request(URL).responseObject(keyPath: "data") { (response: DataResponse) in + expectation.fulfill() + + let weatherResponse = response.result.value + print(weatherResponse?.location) + + if let threeDayForecast = weatherResponse?.threeDayForecast { + for forecast in threeDayForecast { + print(forecast.day) + print(forecast.temperature) + } + } +} +``` + +# Array Responses +If you have an endpoint that returns data in `Array` form you can map it with the following function: +```swift +public func responseArray(queue queue: dispatch_queue_t? = nil, keyPath: String? = nil, completionHandler: DataResponse<[T]> -> Void) -> Self +``` + +For example, if your endpoint returns the following: +``` +[ + { + "conditions": "Partly cloudy", + "day" : "Monday", + "temperature": 20 + }, + { + "conditions": "Showers", + "day" : "Tuesday", + "temperature": 22 + }, + { + "conditions": "Sunny", + "day" : "Wednesday", + "temperature": 28 + } +] +``` +You can request and map it as follows: +```swift +let URL = "https://raw.githubusercontent.com/tristanhimmelman/AlamofireObjectMapper/f583be1121dbc5e9b0381b3017718a70c31054f7/sample_array_json" +Alamofire.request(URL).responseArray { (response: DataResponse<[Forecast]>) in + + let forecastArray = response.result.value + + if let forecastArray = forecastArray { + for forecast in forecastArray { + print(forecast.day) + print(forecast.temperature) + } + } +} + +``` + +# Installation +AlamofireObjectMapper can be added to your project using [CocoaPods](https://cocoapods.org/) by adding the following line to your Podfile: +``` +pod 'AlamofireObjectMapper', '~> 5.0' +``` + +If you're using [Carthage](https://github.com/Carthage/Carthage) you can add a dependency on AlamofireObjectMapper by adding it to your Cartfile: +``` +github "tristanhimmelman/AlamofireObjectMapper" ~> 5.0 +``` diff --git a/Pods/CryptoSwift/LICENSE b/Pods/CryptoSwift/LICENSE new file mode 100644 index 0000000..e52af7d --- /dev/null +++ b/Pods/CryptoSwift/LICENSE @@ -0,0 +1,11 @@ +Copyright (C) 2014-2017 Marcin Krzyżanowski +This software is provided 'as-is', without any express or implied warranty. + +In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +- This notice may not be removed or altered from any source or binary distribution. +- Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).' diff --git a/Pods/CryptoSwift/README.md b/Pods/CryptoSwift/README.md new file mode 100644 index 0000000..a733f2d --- /dev/null +++ b/Pods/CryptoSwift/README.md @@ -0,0 +1,510 @@ +[![Platform](https://img.shields.io/badge/Platforms-iOS%20%7C%20Android%20%7CmacOS%20%7C%20watchOS%20%7C%20tvOS%20%7C%20Linux-4E4E4E.svg?colorA=28a745)](#installation) + +[![Swift support](https://img.shields.io/badge/Swift-3.1%20%7C%203.2%20%7C%204.0%20%7C%204.1%20%7C%204.2%20%7C%205.0-lightgrey.svg?colorA=28a745&colorB=4E4E4E)](#swift-versions-support) +[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/CryptoSwift.svg?style=flat&label=CocoaPods&colorA=28a745&&colorB=4E4E4E)](https://cocoapods.org/pods/CryptoSwift) +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-brightgreen.svg?style=flat&colorA=28a745&&colorB=4E4E4E)](https://github.com/Carthage/Carthage) +[![Accio supported](https://img.shields.io/badge/Accio-supported-brightgreen.svg?style=flat&colorA=28a745&&colorB=4E4E4E)](https://github.com/JamitLabs/Accio) +[![Swift Package Manager compatible](https://img.shields.io/badge/SPM-compatible-brightgreen.svg?style=flat&colorA=28a745&&colorB=4E4E4E)](https://github.com/apple/swift-package-manager) + +[![Twitter](https://img.shields.io/badge/Twitter-@krzyzanowskim-blue.svg?style=flat)](http://twitter.com/krzyzanowskim) + +# CryptoSwift + +Crypto related functions and helpers for [Swift](https://swift.org) implemented in Swift. ([#PureSwift](https://twitter.com/hashtag/pureswift)) + +**Note**: The `master` branch follows the latest currently released **version of Swift**. If you need an earlier version for an older version of Swift, you can specify its version in your `Podfile` or use the code on the branch for that version. Older branches are unsupported. Check [versions](#swift-versions-support) for details. + +--- + +[Requirements](#requirements) | [Features](#features) | [Contribution](#contribution) | [Installation](#installation) | [Swift versions](#swift-versions-support) | [How-to](#how-to) | [Author](#author) | [License](#license) | [Changelog](#changelog) + +## Sponsorship + +If you (or your Company) use this work, please consider [Sponsorship](https://github.com/users/krzyzanowskim/sponsorship). This is the only option to keep the project alive, that is in your own best interrest. + +CryptoSwift isn't backed by a big company and is developer in my spare time that I also use to as a freelancer. + +## Requirements +Good mood + +## Features + +- Easy to use +- Convenient extensions for String and Data +- Support for incremental updates (stream, ...) +- iOS, Android, macOS, AppleTV, watchOS, Linux support + +#### Hash (Digest) + [MD5](http://tools.ietf.org/html/rfc1321) +| [SHA1](http://tools.ietf.org/html/rfc3174) +| [SHA224](http://tools.ietf.org/html/rfc6234) +| [SHA256](http://tools.ietf.org/html/rfc6234) +| [SHA384](http://tools.ietf.org/html/rfc6234) +| [SHA512](http://tools.ietf.org/html/rfc6234) +| [SHA3](http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) + +#### Cyclic Redundancy Check (CRC) + [CRC32](http://en.wikipedia.org/wiki/Cyclic_redundancy_check) +| [CRC32C](http://en.wikipedia.org/wiki/Cyclic_redundancy_check) +| [CRC16](http://en.wikipedia.org/wiki/Cyclic_redundancy_check) + +#### Cipher + [AES-128, AES-192, AES-256](http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf) +| [ChaCha20](http://cr.yp.to/chacha/chacha-20080128.pdf) +| [Rabbit](https://tools.ietf.org/html/rfc4503) +| [Blowfish](https://www.schneier.com/academic/blowfish/) + +#### Message authenticators + [Poly1305](http://cr.yp.to/mac/poly1305-20050329.pdf) +| [HMAC (MD5, SHA1, SHA256)](https://www.ietf.org/rfc/rfc2104.txt) +| [CMAC](https://tools.ietf.org/html/rfc4493) +| [CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC) + +#### Cipher mode of operation +- Electronic codebook ([ECB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29)) +- Cipher-block chaining ([CBC](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29)) +- Propagating Cipher Block Chaining ([PCBC](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Propagating_Cipher_Block_Chaining_.28PCBC.29)) +- Cipher feedback ([CFB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedback_.28CFB.29)) +- Output Feedback ([OFB](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Output_Feedback_.28OFB.29)) +- Counter Mode ([CTR](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29)) +- Galois/Counter Mode ([GCM](https://csrc.nist.gov/publications/detail/sp/800-38d/final)) +- Counter with Cipher Block Chaining-Message Authentication Code ([CCM](https://csrc.nist.gov/publications/detail/sp/800-38c/final)) + +#### Password-Based Key Derivation Function +- [PBKDF1](http://tools.ietf.org/html/rfc2898#section-5.1) (Password-Based Key Derivation Function 1) +- [PBKDF2](http://tools.ietf.org/html/rfc2898#section-5.2) (Password-Based Key Derivation Function 2) +- [HKDF](https://tools.ietf.org/html/rfc5869) (HMAC-based Extract-and-Expand Key Derivation Function) +- [Scrypt](https://tools.ietf.org/html/rfc7914) (The scrypt Password-Based Key Derivation Function) + +#### Data padding + PKCS#5 +| [PKCS#7](http://tools.ietf.org/html/rfc5652#section-6.3) +| [Zero padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#Zero_padding) +| No padding + +#### Authenticated Encryption with Associated Data (AEAD) +- [AEAD\_CHACHA20\_POLY1305](https://tools.ietf.org/html/rfc7539#section-2.8) + +## Why +[Why?](https://github.com/krzyzanowskim/CryptoSwift/issues/5) [Because I can](https://github.com/krzyzanowskim/CryptoSwift/issues/5#issuecomment-53379391). + +## How do I get involved? + +You want to help, great! Go ahead and fork our repo, make your changes and send us a pull request. + +## Contribution + +Check out [CONTRIBUTING.md](CONTRIBUTING.md) for more information on how to help with CryptoSwift. + +- If you found a bug, [open an issue](https://github.com/krzyzanowskim/CryptoSwift/issues). +- If you have a feature request, [open an issue](https://github.com/krzyzanowskim/CryptoSwift/issues). + +## Installation + +To install CryptoSwift, add it as a submodule to your project (on the top level project directory): + + git submodule add https://github.com/krzyzanowskim/CryptoSwift.git + +It is recommended to enable [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) to gain better performance. Non-optimized build results in significantly worse performance. + +#### Embedded Framework + +Embedded frameworks require a minimum deployment target of iOS 8 or OS X Mavericks (10.9). Drag the `CryptoSwift.xcodeproj` file into your Xcode project, and add appropriate framework as a dependency to your target. Now select your App and choose the General tab for the app target. Find *Embedded Binaries* and press "+", then select `CryptoSwift.framework` (iOS, OS X, watchOS or tvOS) + +![](https://cloud.githubusercontent.com/assets/758033/10834511/25a26852-7e9a-11e5-8c01-6cc8f1838459.png) + +Sometimes "embedded framework" option is not available. In that case, you have to add new build phase for the target + +![](https://cloud.githubusercontent.com/assets/758033/18415615/d5edabb0-77f8-11e6-8c94-f41d9fc2b8cb.png) + +##### iOS, macOS, watchOS, tvOS + +In the project, you'll find [single scheme](https://mxcl.dev/PromiseKit/news/2016/08/Multiplatform-Single-Scheme-Xcode-Projects/) for all platforms: +- CryptoSwift + +#### Swift versions support + +- Swift 1.2: branch [swift12](https://github.com/krzyzanowskim/CryptoSwift/tree/swift12) version <= 0.0.13 +- Swift 2.1: branch [swift21](https://github.com/krzyzanowskim/CryptoSwift/tree/swift21) version <= 0.2.3 +- Swift 2.2, 2.3: branch [swift2](https://github.com/krzyzanowskim/CryptoSwift/tree/swift2) version <= 0.5.2 +- Swift 3.1, branch [swift3](https://github.com/krzyzanowskim/CryptoSwift/tree/swift3) version <= 0.6.9 +- Swift 3.2, branch [swift32](https://github.com/krzyzanowskim/CryptoSwift/tree/swift32) version = 0.7.0 +- Swift 4.0, branch [swift4](https://github.com/krzyzanowskim/CryptoSwift/tree/swift4) version <= 0.12.0 +- Swift 4.2, branch [swift42](https://github.com/krzyzanowskim/CryptoSwift/tree/swift42) version <= 0.15.0 +- Swift 5.0, 5.1, branch [master](https://github.com/krzyzanowskim/CryptoSwift/tree/master) + +#### CocoaPods + +You can use [CocoaPods](https://cocoapods.org/pods/CryptoSwift). + +```ruby +pod 'CryptoSwift', '~> 1.0' +``` + +Bear in mind that CocoaPods will build CryptoSwift without [Whole-Module Optimization](https://swift.org/blog/whole-module-optimizations/) that may impact performance. You can change it manually after installation, or use [cocoapods-wholemodule](https://github.com/jedlewison/cocoapods-wholemodule) plugin. + +#### Carthage +You can use [Carthage](https://github.com/Carthage/Carthage). +Specify in Cartfile: + +```ruby +github "krzyzanowskim/CryptoSwift" +``` + +Run `carthage` to build the framework and drag the built CryptoSwift.framework into your Xcode project. Follow [build instructions](https://github.com/Carthage/Carthage#getting-started). [Common issues](https://github.com/krzyzanowskim/CryptoSwift/issues/492#issuecomment-330822874). + +#### Swift Package Manager + +You can use [Swift Package Manager](https://swift.org/package-manager/) and specify dependency in `Package.swift` by adding this: + +```swift +.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0")) +``` + +See: [Package.swift - manual](http://blog.krzyzanowskim.com/2016/08/09/package-swift-manual/) + +#### Accio +You can use [Accio](https://github.com/JamitLabs/Accio). Specify in `Package.swift`: + +```swift +.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMajor(from: "1.0.0")), +``` + +Then run `accio update`. + +--- + +## How-to + +* [Basics (data types, conversion, ...)](#basics) +* [Digest (MD5, SHA...)](#calculate-digest) +* [Message authenticators (HMAC, CMAC...)](#message-authenticators-1) +* [Password-Based Key Derivation Function (PBKDF2, ...)](#password-based-key-derivation-functions) +* [HMAC-based Key Derivation Function (HKDF)](#hmac-based-key-derivation-function) +* [Data Padding](#data-padding) +* [ChaCha20](#chacha20) +* [Rabbit](#rabbit) +* [Blowfish](#blowfish) +* [AES - Advanced Encryption Standard](#aes) +* [AES-GCM](#aes-gcm) +* [Authenticated Encryption with Associated Data (AEAD)](#aead) + +also check [Playground](/CryptoSwift.playground/Contents.swift) + +##### Basics + +```swift +import CryptoSwift +``` + +CryptoSwift uses array of bytes aka `Array` as a base type for all operations. Every data may be converted to a stream of bytes. You will find convenience functions that accept `String` or `Data`, and it will be internally converted to the array of bytes. + +##### Data types conversion + +For your convenience, **CryptoSwift** provides two functions to easily convert an array of bytes to `Data` or `Data` to an array of bytes: + +Data from bytes: + +```swift +let data = Data( [0x01, 0x02, 0x03]) +``` + +`Data` to `Array` + +```swift +let bytes = data.bytes // [1,2,3] +``` + +[Hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) encoding: + +```swift +let bytes = Array(hex: "0x010203") // [1,2,3] +let hex = bytes.toHexString() // "010203" +``` + +Build bytes out of `String` +```swift +let bytes: Array = "cipherkey".bytes // Array("cipherkey".utf8) +``` + +Also... check out helpers that work with **Base64** encoded data: +```swift +"aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64ToString(cipher) +"aPf/i9th9iX+vf49eR7PYk2q7S5xmm3jkRLejgzHNJs=".decryptBase64(cipher) +bytes.toBase64() +``` + +##### Calculate Digest + +Hashing a data or array of bytes (aka `Array`) +```swift +/* Hash struct usage */ +let bytes:Array = [0x01, 0x02, 0x03] +let digest = input.md5() +let digest = Digest.md5(bytes) +``` + +```swift +let data = Data( [0x01, 0x02, 0x03]) + +let hash = data.md5() +let hash = data.sha1() +let hash = data.sha224() +let hash = data.sha256() +let hash = data.sha384() +let hash = data.sha512() +``` +```swift +do { + var digest = MD5() + let partial1 = try digest.update(withBytes: [0x31, 0x32]) + let partial2 = try digest.update(withBytes: [0x33]) + let result = try digest.finish() +} catch { } +``` + +Hashing a String and printing result + +```swift +let hash = "123".md5() // "123".bytes.md5() +``` + +##### Calculate CRC + +```swift +bytes.crc16() +data.crc16() + +bytes.crc32() +data.crc32() +``` + +##### Message authenticators + +```swift +// Calculate Message Authentication Code (MAC) for message +let key:Array = [1,2,3,4,5,6,7,8,9,10,...] + +try Poly1305(key: key).authenticate(bytes) +try HMAC(key: key, variant: .sha256).authenticate(bytes) +try CMAC(key: key).authenticate(bytes) +``` + +##### Password-Based Key Derivation Functions + +```swift +let password: Array = Array("s33krit".utf8) +let salt: Array = Array("nacllcan".utf8) + +let key = try PKCS5.PBKDF2(password: password, salt: salt, iterations: 4096, keyLength: 32, variant: .sha256).calculate() +``` + +```swift +let password: Array = Array("s33krit".utf8) +let salt: Array = Array("nacllcan".utf8) +// Scrypt implementation does not implement work parallelization, so `p` parameter will +// increase the work time even in multicore systems +let key = try Scrypt(password: password, salt: salt, dkLen: 64, N: 16384, r: 8, p: 1).calculate() +``` + +##### HMAC-based Key Derivation Function + +```swift +let password: Array = Array("s33krit".utf8) +let salt: Array = Array("nacllcan".utf8) + +let key = try HKDF(password: password, salt: salt, variant: .sha256).calculate() +``` + + +##### Data Padding + +Some content-encryption algorithms assume the input length is a multiple of `k` octets, where `k` is greater than one. For such algorithms, the input shall be padded. + +```swift +Padding.pkcs7.add(to: bytes, blockSize: AES.blockSize) +``` + +#### Working with Ciphers +##### ChaCha20 + +```swift +let encrypted = try ChaCha20(key: key, iv: iv).encrypt(message) +let decrypted = try ChaCha20(key: key, iv: iv).decrypt(encrypted) +``` + +##### Rabbit + +```swift +let encrypted = try Rabbit(key: key, iv: iv).encrypt(message) +let decrypted = try Rabbit(key: key, iv: iv).decrypt(encrypted) +``` +##### Blowfish + +```swift +let encrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(message) +let decrypted = try Blowfish(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted) +``` + +##### AES + +Notice regarding padding: *Manual padding of data is optional, and CryptoSwift is using PKCS7 padding by default. If you need to manually disable/enable padding, you can do this by setting parameter for __AES__ class* + +Variant of AES encryption (AES-128, AES-192, AES-256) depends on given key length: + +- AES-128 = 16 bytes +- AES-192 = 24 bytes +- AES-256 = 32 bytes + +AES-256 example +```swift +try AES(key: [1,2,3,...,32], blockMode: CBC(iv: [1,2,3,...,16]), padding: .pkcs7) +``` + +###### All at once +```swift +do { + let aes = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap") // aes128 + let ciphertext = try aes.encrypt(Array("Nullam quis risus eget urna mollis ornare vel eu leo.".utf8)) +} catch { } +``` + +###### Incremental updates + +Incremental operations use instance of Cryptor and encrypt/decrypt one part at a time, this way you can save on memory for large files. + +```swift +do { + var encryptor = try AES(key: "keykeykeykeykeyk", iv: "drowssapdrowssap").makeEncryptor() + + var ciphertext = Array() + // aggregate partial results + ciphertext += try encryptor.update(withBytes: Array("Nullam quis risus ".utf8)) + ciphertext += try encryptor.update(withBytes: Array("eget urna mollis ".utf8)) + ciphertext += try encryptor.update(withBytes: Array("ornare vel eu leo.".utf8)) + // finish at the end + ciphertext += try encryptor.finish() + + print(ciphertext.toHexString()) +} catch { + print(error) +} +``` + +See [Playground](/CryptoSwift.playground/Contents.swift) for sample code that work with stream. + +###### AES Advanced usage +```swift +let input: Array = [0,1,2,3,4,5,6,7,8,9] + +let key: Array = [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00] +let iv: Array = // Random bytes of `AES.blockSize` length + +do { + let encrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).encrypt(input) + let decrypted = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7).decrypt(encrypted) +} catch { + print(error) +} +``` + +AES without data padding + +```swift +let input: Array = [0,1,2,3,4,5,6,7,8,9] +let encrypted: Array = try! AES(key: Array("secret0key000000".utf8), blockMode: CBC(iv: Array("0123456789012345".utf8)), padding: .noPadding).encrypt(input) +``` + +Using convenience extensions + +```swift +let plain = Data( [0x01, 0x02, 0x03]) +let encrypted = try! plain.encrypt(ChaCha20(key: key, iv: iv)) +let decrypted = try! encrypted.decrypt(ChaCha20(key: key, iv: iv)) +``` + +##### AES-GCM + +The result of Galois/Counter Mode (GCM) encryption is ciphertext and **authentication tag**, that is later used to decryption. + +encryption + +```swift +do { + // In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want. + let gcm = GCM(iv: iv, mode: .combined) + let aes = try AES(key: key, blockMode: gcm, padding: .noPadding) + let encrypted = try aes.encrypt(plaintext) + let tag = gcm.authenticationTag +catch { + // failed +} +``` + +decryption + +```swift +do { + // In combined mode, the authentication tag is appended to the encrypted message. This is usually what you want. + let gcm = GCM(iv: iv, mode: .combined) + let aes = try AES(key: key, blockMode: gcm, padding: .noPadding) + return try aes.decrypt(encrypted) +} catch { + // failed +} +``` + +**Note**: GCM instance is not intended to be reused. So you can't use the same `GCM` instance from encoding to also perform decoding. + +##### AES-CCM + +The result of Counter with Cipher Block Chaining-Message Authentication Code encryption is ciphertext and **authentication tag**, that is later used to decryption. + +```swift +do { + // The authentication tag is appended to the encrypted message. + let tagLength = 8 + let ccm = CCM(iv: iv, tagLength: tagLength, messageLength: ciphertext.count - tagLength, additionalAuthenticatedData: data) + let aes = try AES(key: key, blockMode: ccm, padding: .noPadding) + return try aes.decrypt(encrypted) +} catch { + // failed +} +``` + +Check documentation or CCM specification for valid parameters for CCM. + +##### AEAD + +```swift +let encrypt = try AEADChaCha20Poly1305.encrypt(plaintext, key: key, iv: nonce, authenticationHeader: header) +let decrypt = try AEADChaCha20Poly1305.decrypt(ciphertext, key: key, iv: nonce, authenticationHeader: header, authenticationTag: tagArr: tag) +``` + +## Author + +CryptoSwift is owned and maintained by [Marcin Krzyżanowski](http://www.krzyzanowskim.com) + +You can follow me on Twitter at [@krzyzanowskim](http://twitter.com/krzyzanowskim) for project updates and releases. + +# Cryptography Notice + +This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See http://www.wassenaar.org/ for more information. + +## License + +Copyright (C) 2014-2017 Marcin Krzyżanowski +This software is provided 'as-is', without any express or implied warranty. + +In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, **an acknowledgment in the product documentation is required**. +- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +- This notice may not be removed or altered from any source or binary distribution. +- Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).' + +## Changelog + +See [CHANGELOG](./CHANGELOG) file. diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEAD.swift b/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEAD.swift new file mode 100644 index 0000000..6d85c04 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEAD.swift @@ -0,0 +1,40 @@ +// +// AEAD.swift +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// +// + +// https://www.iana.org/assignments/aead-parameters/aead-parameters.xhtml + +/// Authenticated Encryption with Associated Data (AEAD) +public protocol AEAD { + static var kLen: Int { get } // key length + static var ivRange: Range { get } // nonce length +} + +extension AEAD { + static func calculateAuthenticationTag(authenticator: Authenticator, cipherText: Array, authenticationHeader: Array) throws -> Array { + let headerPadding = ((16 - (authenticationHeader.count & 0xf)) & 0xf) + let cipherPadding = ((16 - (cipherText.count & 0xf)) & 0xf) + + var mac = authenticationHeader + mac += Array(repeating: 0, count: headerPadding) + mac += cipherText + mac += Array(repeating: 0, count: cipherPadding) + mac += UInt64(bigEndian: UInt64(authenticationHeader.count)).bytes() + mac += UInt64(bigEndian: UInt64(cipherText.count)).bytes() + + return try authenticator.authenticate(mac) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEADChaCha20Poly1305.swift b/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEADChaCha20Poly1305.swift new file mode 100644 index 0000000..085f031 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/AEAD/AEADChaCha20Poly1305.swift @@ -0,0 +1,59 @@ +// +// ChaCha20Poly1305.swift +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// +// +// https://tools.ietf.org/html/rfc7539#section-2.8.1 + +/// AEAD_CHACHA20_POLY1305 +public final class AEADChaCha20Poly1305: AEAD { + public static let kLen = 32 // key length + public static var ivRange = Range(12...12) + + /// Authenticated encryption + public static func encrypt(_ plainText: Array, key: Array, iv: Array, authenticationHeader: Array) throws -> (cipherText: Array, authenticationTag: Array) { + let cipher = try ChaCha20(key: key, iv: iv) + + var polykey = Array(repeating: 0, count: kLen) + var toEncrypt = polykey + polykey = try cipher.encrypt(polykey) + toEncrypt += polykey + toEncrypt += plainText + + let fullCipherText = try cipher.encrypt(toEncrypt) + let cipherText = Array(fullCipherText.dropFirst(64)) + + let tag = try calculateAuthenticationTag(authenticator: Poly1305(key: polykey), cipherText: cipherText, authenticationHeader: authenticationHeader) + return (cipherText, tag) + } + + /// Authenticated decryption + public static func decrypt(_ cipherText: Array, key: Array, iv: Array, authenticationHeader: Array, authenticationTag: Array) throws -> (plainText: Array, success: Bool) { + let chacha = try ChaCha20(key: key, iv: iv) + + let polykey = try chacha.encrypt(Array(repeating: 0, count: self.kLen)) + let mac = try calculateAuthenticationTag(authenticator: Poly1305(key: polykey), cipherText: cipherText, authenticationHeader: authenticationHeader) + guard mac == authenticationTag else { + return (cipherText, false) + } + + var toDecrypt = Array(reserveCapacity: cipherText.count + 64) + toDecrypt += polykey + toDecrypt += polykey + toDecrypt += cipherText + let fullPlainText = try chacha.decrypt(toDecrypt) + let plainText = Array(fullPlainText.dropFirst(64)) + return (plainText, true) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/AES.Cryptors.swift b/Pods/CryptoSwift/Sources/CryptoSwift/AES.Cryptors.swift new file mode 100644 index 0000000..617ff7d --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/AES.Cryptors.swift @@ -0,0 +1,35 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// MARK: Cryptors + +extension AES: Cryptors { + public func makeEncryptor() throws -> Cryptor & Updatable { + let worker = try blockMode.worker(blockSize: AES.blockSize, cipherOperation: encrypt) + if worker is StreamModeWorker { + return try StreamEncryptor(blockSize: AES.blockSize, padding: padding, worker) + } + return try BlockEncryptor(blockSize: AES.blockSize, padding: padding, worker) + } + + public func makeDecryptor() throws -> Cryptor & Updatable { + let cipherOperation: CipherOperationOnBlock = blockMode.options.contains(.useEncryptToDecrypt) == true ? encrypt : decrypt + let worker = try blockMode.worker(blockSize: AES.blockSize, cipherOperation: cipherOperation) + if worker is StreamModeWorker { + return try StreamDecryptor(blockSize: AES.blockSize, padding: padding, worker) + } + return try BlockDecryptor(blockSize: AES.blockSize, padding: padding, worker) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/AES.swift b/Pods/CryptoSwift/Sources/CryptoSwift/AES.swift new file mode 100644 index 0000000..bd4e583 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/AES.swift @@ -0,0 +1,539 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// Implementation of Gladman algorithm http://www.gladman.me.uk/AES +// + +/// The Advanced Encryption Standard (AES) +public final class AES: BlockCipher { + public enum Error: Swift.Error { + /// Invalid key + case invalidKeySize + /// Data padding is required + case dataPaddingRequired + /// Invalid Data + case invalidData + } + + public enum Variant: Int { + case aes128 = 1, aes192, aes256 + + var Nk: Int { // Nk words + [4, 6, 8][self.rawValue - 1] + } + + var Nb: Int { // Nb words + 4 + } + + var Nr: Int { // Nr + self.Nk + 6 + } + } + + private let variantNr: Int + private let variantNb: Int + private let variantNk: Int + + public static let blockSize: Int = 16 // 128 /8 + public let keySize: Int + + /// AES Variant + public let variant: Variant + + // Parameters + let key: Key + let blockMode: BlockMode + let padding: Padding + + // + private lazy var expandedKey: Array> = self.expandKey(self.key, variant: self.variant) + private lazy var expandedKeyInv: Array> = self.expandKeyInv(self.key, variant: self.variant) + + private lazy var sBoxes: (sBox: Array, invSBox: Array) = self.calculateSBox() + private lazy var sBox: Array = self.sBoxes.sBox + private lazy var sBoxInv: Array = self.sBoxes.invSBox + + // Parameters for Linear Congruence Generators + private static let Rcon: Array = [ + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, + 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, + 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, + 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, + 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, + 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, + 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, + 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, + 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, + 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, + 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, + 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, + 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, + 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, + 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d + ] + + private static let T0: Array = [0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0xdf2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x3010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0xbf0f0fb, 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x2f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x8f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, 0xc040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0xf05050a, 0xb59a9a2f, 0x907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x0, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, 0x10f9f9e9, 0x6020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x4f5f5f1, 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, 0x1affffe5, 0xef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0xa06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac, 0x7f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x5030306, 0x1f6f6f7, 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c] + private static let T0_INV: Array = [0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 0x2752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, 0x728ebb2, 0x3c2b52f, 0x9a7bc586, 0xa50837d3, 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x69f715e, 0x51106ebd, 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 0x55dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x0, 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0xfe75793, 0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 0xaba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0xb0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0xd927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x97826cd, 0xf418596e, 0x1b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x8cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, 0xf7daec41, 0xe50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, 0x4ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0xc25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0] + private static let T1: Array = [0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x1010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x5050a0f, 0x9a9a2fb5, 0x7070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, 0x5353a6f5, 0xd1d1b968, 0x0, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, 0xf9f9e910, 0x2020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0xc0c1814, 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0xb0b161d, 0xdbdbad76, 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0xa0a141e, 0x494992db, 0x6060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x8081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x3030605, 0xf6f6f701, 0xe0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, 0x8c8c038f, 0xa1a159f8, 0x89890980, 0xd0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 0x2d2d5a77, 0xf0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a] + private static let T1_INV: Array = [0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x3e34b93, 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0xeea4598, 0xc0fe5de1, 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x24b72e2, 0x8f1fe357, 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x837d3a5, 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, 0x8a213ef9, 0x6dd963d, 0x53eddae, 0xbde64d46, 0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, 0xa7ca147, 0xf427ce9, 0x1e84f8c9, 0x0, 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0xd090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x775af4c, 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0xbd49836, 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x99fead4, 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c, 0xca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x1a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042] + private static let T2: Array = [0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x1020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x4080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x50a0f05, 0x9a2fb59a, 0x70e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x9121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, 0x53a6f553, 0xd1b968d1, 0x0, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, 0xf9e910f9, 0x2040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0xc18140c, 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0xb161d0b, 0xdbad76db, 0xe0db3be0, 0x32645632, 0x3a744e3a, 0xa141e0a, 0x4992db49, 0x60c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x8101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x3060503, 0xf6f701f6, 0xe1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, 0x8c038f8c, 0xa159f8a1, 0x89098089, 0xd1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 0x2d5a772d, 0xf1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16] + private static let T2_INV: Array = [0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 0xcc889176, 0x2f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x8f9942b, 0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, 0x2830f287, 0xbf23b2a5, 0x302ba6a, 0x16ed5c82, 0xcf8a2b1c, 0x79a792b4, 0x7f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x506d5be, 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 0xc471055d, 0x6046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x0, 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0xefdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739, 0xf0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, 0xa0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x90e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, 0x1f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x4f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0xbfb2e41, 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0xdff4195, 0xa8397101, 0xc08deb3, 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257] + private static let T3: Array = [0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x2030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x80c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0xa0f0505, 0x2fb59a9a, 0xe090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, 0xa6f55353, 0xb968d1d1, 0x0, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, 0xe910f9f9, 0x4060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x58a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, 0x3bab9090, 0xb838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0xc0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x18c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, 0x61dcbdbd, 0xd868b8b, 0xf858a8a, 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x6050303, 0xf701f6f6, 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x7898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, 0x38f8c8c, 0x59f8a1a1, 0x9808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616] + private static let T3_INV: Array = [0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x3e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, 0x30f28728, 0x23b2a5bf, 0x2ba6a03, 0xed5c8216, 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x6d5be05, 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x532e18a, 0xa475ebf6, 0xb39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 0x71055dc4, 0x46fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x7888b89, 0xe7385b19, 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x0, 0x9838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, 0xf563885, 0x3d1ed5ae, 0x3627392d, 0xa64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, 0xcb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0xe0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, 0xdec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165, 0x9d04ea5e, 0x15d358c, 0xfa737487, 0xfb2e410b, 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x8deb30c, 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8] + private static let U1: Array = [0x0, 0xb0d090e, 0x161a121c, 0x1d171b12, 0x2c342438, 0x27392d36, 0x3a2e3624, 0x31233f2a, 0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362, 0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a, 0xb0d090e0, 0xbbdd99ee, 0xa6ca82fc, 0xadc78bf2, 0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca, 0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382, 0xc48cfca8, 0xcf81f5a6, 0xd296eeb4, 0xd99be7ba, 0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9, 0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1, 0x23d373ab, 0x28de7aa5, 0x35c961b7, 0x3ec468b9, 0xfe75793, 0x4ea5e9d, 0x19fd458f, 0x12f04c81, 0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029, 0xe75f8f03, 0xec52860d, 0xf1459d1f, 0xfa489411, 0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859, 0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61, 0xf66d76ad, 0xfd607fa3, 0xe07764b1, 0xeb7a6dbf, 0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987, 0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf, 0x82311ae5, 0x893c13eb, 0x942b08f9, 0x9f2601f7, 0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f, 0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967, 0x1ed5ae3d, 0x15d8a733, 0x8cfbc21, 0x3c2b52f, 0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117, 0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664, 0xa1e2694e, 0xaaef6040, 0xb7f87b52, 0xbcf5725c, 0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14, 0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c, 0x3d06dd96, 0x360bd498, 0x2b1ccf8a, 0x2011c684, 0x1132f9ae, 0x1a3ff0a0, 0x728ebb2, 0xc25e2bc, 0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4, 0x495ab1de, 0x4257b8d0, 0x5f40a3c2, 0x544daacc, 0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753, 0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b, 0xafb2a431, 0xa4bfad3f, 0xb9a8b62d, 0xb2a5bf23, 0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b, 0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3, 0x6b3e5899, 0x60335197, 0x7d244a85, 0x7629438b, 0x1f6234d1, 0x146f3ddf, 0x97826cd, 0x2752fc3, 0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb, 0x8c61d79a, 0x876cde94, 0x9a7bc586, 0x9176cc88, 0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0, 0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8, 0xf83dbbd2, 0xf330b2dc, 0xee27a9ce, 0xe52aa0c0, 0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68, 0x10856342, 0x1b886a4c, 0x69f715e, 0xd927850, 0x64d90f0a, 0x6fd40604, 0x72c31d16, 0x79ce1418, 0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020, 0x1b79aec, 0xaba93e2, 0x17ad88f0, 0x1ca081fe, 0x2d83bed4, 0x268eb7da, 0x3b99acc8, 0x3094a5c6, 0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e, 0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6, 0xb1670a0c, 0xba6a0302, 0xa77d1810, 0xac70111e, 0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526, 0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e, 0xc53b6644, 0xce366f4a, 0xd3217458, 0xd82c7d56, 0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25, 0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d, 0x2264e947, 0x2969e049, 0x347efb5b, 0x3f73f255, 0xe50cd7f, 0x55dc471, 0x184adf63, 0x1347d66d, 0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5, 0xe6e815ef, 0xede51ce1, 0xf0f207f3, 0xfbff0efd, 0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5, 0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d] + private static let U2: Array = [0x0, 0xd090e0b, 0x1a121c16, 0x171b121d, 0x3424382c, 0x392d3627, 0x2e36243a, 0x233f2a31, 0x68487058, 0x65417e53, 0x725a6c4e, 0x7f536245, 0x5c6c4874, 0x5165467f, 0x467e5462, 0x4b775a69, 0xd090e0b0, 0xdd99eebb, 0xca82fca6, 0xc78bf2ad, 0xe4b4d89c, 0xe9bdd697, 0xfea6c48a, 0xf3afca81, 0xb8d890e8, 0xb5d19ee3, 0xa2ca8cfe, 0xafc382f5, 0x8cfca8c4, 0x81f5a6cf, 0x96eeb4d2, 0x9be7bad9, 0xbb3bdb7b, 0xb632d570, 0xa129c76d, 0xac20c966, 0x8f1fe357, 0x8216ed5c, 0x950dff41, 0x9804f14a, 0xd373ab23, 0xde7aa528, 0xc961b735, 0xc468b93e, 0xe757930f, 0xea5e9d04, 0xfd458f19, 0xf04c8112, 0x6bab3bcb, 0x66a235c0, 0x71b927dd, 0x7cb029d6, 0x5f8f03e7, 0x52860dec, 0x459d1ff1, 0x489411fa, 0x3e34b93, 0xeea4598, 0x19f15785, 0x14f8598e, 0x37c773bf, 0x3ace7db4, 0x2dd56fa9, 0x20dc61a2, 0x6d76adf6, 0x607fa3fd, 0x7764b1e0, 0x7a6dbfeb, 0x595295da, 0x545b9bd1, 0x434089cc, 0x4e4987c7, 0x53eddae, 0x837d3a5, 0x1f2cc1b8, 0x1225cfb3, 0x311ae582, 0x3c13eb89, 0x2b08f994, 0x2601f79f, 0xbde64d46, 0xb0ef434d, 0xa7f45150, 0xaafd5f5b, 0x89c2756a, 0x84cb7b61, 0x93d0697c, 0x9ed96777, 0xd5ae3d1e, 0xd8a73315, 0xcfbc2108, 0xc2b52f03, 0xe18a0532, 0xec830b39, 0xfb981924, 0xf691172f, 0xd64d768d, 0xdb447886, 0xcc5f6a9b, 0xc1566490, 0xe2694ea1, 0xef6040aa, 0xf87b52b7, 0xf5725cbc, 0xbe0506d5, 0xb30c08de, 0xa4171ac3, 0xa91e14c8, 0x8a213ef9, 0x872830f2, 0x903322ef, 0x9d3a2ce4, 0x6dd963d, 0xbd49836, 0x1ccf8a2b, 0x11c68420, 0x32f9ae11, 0x3ff0a01a, 0x28ebb207, 0x25e2bc0c, 0x6e95e665, 0x639ce86e, 0x7487fa73, 0x798ef478, 0x5ab1de49, 0x57b8d042, 0x40a3c25f, 0x4daacc54, 0xdaec41f7, 0xd7e54ffc, 0xc0fe5de1, 0xcdf753ea, 0xeec879db, 0xe3c177d0, 0xf4da65cd, 0xf9d36bc6, 0xb2a431af, 0xbfad3fa4, 0xa8b62db9, 0xa5bf23b2, 0x86800983, 0x8b890788, 0x9c921595, 0x919b1b9e, 0xa7ca147, 0x775af4c, 0x106ebd51, 0x1d67b35a, 0x3e58996b, 0x33519760, 0x244a857d, 0x29438b76, 0x6234d11f, 0x6f3ddf14, 0x7826cd09, 0x752fc302, 0x5610e933, 0x5b19e738, 0x4c02f525, 0x410bfb2e, 0x61d79a8c, 0x6cde9487, 0x7bc5869a, 0x76cc8891, 0x55f3a2a0, 0x58faacab, 0x4fe1beb6, 0x42e8b0bd, 0x99fead4, 0x496e4df, 0x138df6c2, 0x1e84f8c9, 0x3dbbd2f8, 0x30b2dcf3, 0x27a9ceee, 0x2aa0c0e5, 0xb1477a3c, 0xbc4e7437, 0xab55662a, 0xa65c6821, 0x85634210, 0x886a4c1b, 0x9f715e06, 0x9278500d, 0xd90f0a64, 0xd406046f, 0xc31d1672, 0xce141879, 0xed2b3248, 0xe0223c43, 0xf7392e5e, 0xfa302055, 0xb79aec01, 0xba93e20a, 0xad88f017, 0xa081fe1c, 0x83bed42d, 0x8eb7da26, 0x99acc83b, 0x94a5c630, 0xdfd29c59, 0xd2db9252, 0xc5c0804f, 0xc8c98e44, 0xebf6a475, 0xe6ffaa7e, 0xf1e4b863, 0xfcedb668, 0x670a0cb1, 0x6a0302ba, 0x7d1810a7, 0x70111eac, 0x532e349d, 0x5e273a96, 0x493c288b, 0x44352680, 0xf427ce9, 0x24b72e2, 0x155060ff, 0x18596ef4, 0x3b6644c5, 0x366f4ace, 0x217458d3, 0x2c7d56d8, 0xca1377a, 0x1a83971, 0x16b32b6c, 0x1bba2567, 0x38850f56, 0x358c015d, 0x22971340, 0x2f9e1d4b, 0x64e94722, 0x69e04929, 0x7efb5b34, 0x73f2553f, 0x50cd7f0e, 0x5dc47105, 0x4adf6318, 0x47d66d13, 0xdc31d7ca, 0xd138d9c1, 0xc623cbdc, 0xcb2ac5d7, 0xe815efe6, 0xe51ce1ed, 0xf207f3f0, 0xff0efdfb, 0xb479a792, 0xb970a999, 0xae6bbb84, 0xa362b58f, 0x805d9fbe, 0x8d5491b5, 0x9a4f83a8, 0x97468da3] + private static let U3: Array = [0x0, 0x90e0b0d, 0x121c161a, 0x1b121d17, 0x24382c34, 0x2d362739, 0x36243a2e, 0x3f2a3123, 0x48705868, 0x417e5365, 0x5a6c4e72, 0x5362457f, 0x6c48745c, 0x65467f51, 0x7e546246, 0x775a694b, 0x90e0b0d0, 0x99eebbdd, 0x82fca6ca, 0x8bf2adc7, 0xb4d89ce4, 0xbdd697e9, 0xa6c48afe, 0xafca81f3, 0xd890e8b8, 0xd19ee3b5, 0xca8cfea2, 0xc382f5af, 0xfca8c48c, 0xf5a6cf81, 0xeeb4d296, 0xe7bad99b, 0x3bdb7bbb, 0x32d570b6, 0x29c76da1, 0x20c966ac, 0x1fe3578f, 0x16ed5c82, 0xdff4195, 0x4f14a98, 0x73ab23d3, 0x7aa528de, 0x61b735c9, 0x68b93ec4, 0x57930fe7, 0x5e9d04ea, 0x458f19fd, 0x4c8112f0, 0xab3bcb6b, 0xa235c066, 0xb927dd71, 0xb029d67c, 0x8f03e75f, 0x860dec52, 0x9d1ff145, 0x9411fa48, 0xe34b9303, 0xea45980e, 0xf1578519, 0xf8598e14, 0xc773bf37, 0xce7db43a, 0xd56fa92d, 0xdc61a220, 0x76adf66d, 0x7fa3fd60, 0x64b1e077, 0x6dbfeb7a, 0x5295da59, 0x5b9bd154, 0x4089cc43, 0x4987c74e, 0x3eddae05, 0x37d3a508, 0x2cc1b81f, 0x25cfb312, 0x1ae58231, 0x13eb893c, 0x8f9942b, 0x1f79f26, 0xe64d46bd, 0xef434db0, 0xf45150a7, 0xfd5f5baa, 0xc2756a89, 0xcb7b6184, 0xd0697c93, 0xd967779e, 0xae3d1ed5, 0xa73315d8, 0xbc2108cf, 0xb52f03c2, 0x8a0532e1, 0x830b39ec, 0x981924fb, 0x91172ff6, 0x4d768dd6, 0x447886db, 0x5f6a9bcc, 0x566490c1, 0x694ea1e2, 0x6040aaef, 0x7b52b7f8, 0x725cbcf5, 0x506d5be, 0xc08deb3, 0x171ac3a4, 0x1e14c8a9, 0x213ef98a, 0x2830f287, 0x3322ef90, 0x3a2ce49d, 0xdd963d06, 0xd498360b, 0xcf8a2b1c, 0xc6842011, 0xf9ae1132, 0xf0a01a3f, 0xebb20728, 0xe2bc0c25, 0x95e6656e, 0x9ce86e63, 0x87fa7374, 0x8ef47879, 0xb1de495a, 0xb8d04257, 0xa3c25f40, 0xaacc544d, 0xec41f7da, 0xe54ffcd7, 0xfe5de1c0, 0xf753eacd, 0xc879dbee, 0xc177d0e3, 0xda65cdf4, 0xd36bc6f9, 0xa431afb2, 0xad3fa4bf, 0xb62db9a8, 0xbf23b2a5, 0x80098386, 0x8907888b, 0x9215959c, 0x9b1b9e91, 0x7ca1470a, 0x75af4c07, 0x6ebd5110, 0x67b35a1d, 0x58996b3e, 0x51976033, 0x4a857d24, 0x438b7629, 0x34d11f62, 0x3ddf146f, 0x26cd0978, 0x2fc30275, 0x10e93356, 0x19e7385b, 0x2f5254c, 0xbfb2e41, 0xd79a8c61, 0xde94876c, 0xc5869a7b, 0xcc889176, 0xf3a2a055, 0xfaacab58, 0xe1beb64f, 0xe8b0bd42, 0x9fead409, 0x96e4df04, 0x8df6c213, 0x84f8c91e, 0xbbd2f83d, 0xb2dcf330, 0xa9ceee27, 0xa0c0e52a, 0x477a3cb1, 0x4e7437bc, 0x55662aab, 0x5c6821a6, 0x63421085, 0x6a4c1b88, 0x715e069f, 0x78500d92, 0xf0a64d9, 0x6046fd4, 0x1d1672c3, 0x141879ce, 0x2b3248ed, 0x223c43e0, 0x392e5ef7, 0x302055fa, 0x9aec01b7, 0x93e20aba, 0x88f017ad, 0x81fe1ca0, 0xbed42d83, 0xb7da268e, 0xacc83b99, 0xa5c63094, 0xd29c59df, 0xdb9252d2, 0xc0804fc5, 0xc98e44c8, 0xf6a475eb, 0xffaa7ee6, 0xe4b863f1, 0xedb668fc, 0xa0cb167, 0x302ba6a, 0x1810a77d, 0x111eac70, 0x2e349d53, 0x273a965e, 0x3c288b49, 0x35268044, 0x427ce90f, 0x4b72e202, 0x5060ff15, 0x596ef418, 0x6644c53b, 0x6f4ace36, 0x7458d321, 0x7d56d82c, 0xa1377a0c, 0xa8397101, 0xb32b6c16, 0xba25671b, 0x850f5638, 0x8c015d35, 0x97134022, 0x9e1d4b2f, 0xe9472264, 0xe0492969, 0xfb5b347e, 0xf2553f73, 0xcd7f0e50, 0xc471055d, 0xdf63184a, 0xd66d1347, 0x31d7cadc, 0x38d9c1d1, 0x23cbdcc6, 0x2ac5d7cb, 0x15efe6e8, 0x1ce1ede5, 0x7f3f0f2, 0xefdfbff, 0x79a792b4, 0x70a999b9, 0x6bbb84ae, 0x62b58fa3, 0x5d9fbe80, 0x5491b58d, 0x4f83a89a, 0x468da397] + private static let U4: Array = [0x0, 0xe0b0d09, 0x1c161a12, 0x121d171b, 0x382c3424, 0x3627392d, 0x243a2e36, 0x2a31233f, 0x70586848, 0x7e536541, 0x6c4e725a, 0x62457f53, 0x48745c6c, 0x467f5165, 0x5462467e, 0x5a694b77, 0xe0b0d090, 0xeebbdd99, 0xfca6ca82, 0xf2adc78b, 0xd89ce4b4, 0xd697e9bd, 0xc48afea6, 0xca81f3af, 0x90e8b8d8, 0x9ee3b5d1, 0x8cfea2ca, 0x82f5afc3, 0xa8c48cfc, 0xa6cf81f5, 0xb4d296ee, 0xbad99be7, 0xdb7bbb3b, 0xd570b632, 0xc76da129, 0xc966ac20, 0xe3578f1f, 0xed5c8216, 0xff41950d, 0xf14a9804, 0xab23d373, 0xa528de7a, 0xb735c961, 0xb93ec468, 0x930fe757, 0x9d04ea5e, 0x8f19fd45, 0x8112f04c, 0x3bcb6bab, 0x35c066a2, 0x27dd71b9, 0x29d67cb0, 0x3e75f8f, 0xdec5286, 0x1ff1459d, 0x11fa4894, 0x4b9303e3, 0x45980eea, 0x578519f1, 0x598e14f8, 0x73bf37c7, 0x7db43ace, 0x6fa92dd5, 0x61a220dc, 0xadf66d76, 0xa3fd607f, 0xb1e07764, 0xbfeb7a6d, 0x95da5952, 0x9bd1545b, 0x89cc4340, 0x87c74e49, 0xddae053e, 0xd3a50837, 0xc1b81f2c, 0xcfb31225, 0xe582311a, 0xeb893c13, 0xf9942b08, 0xf79f2601, 0x4d46bde6, 0x434db0ef, 0x5150a7f4, 0x5f5baafd, 0x756a89c2, 0x7b6184cb, 0x697c93d0, 0x67779ed9, 0x3d1ed5ae, 0x3315d8a7, 0x2108cfbc, 0x2f03c2b5, 0x532e18a, 0xb39ec83, 0x1924fb98, 0x172ff691, 0x768dd64d, 0x7886db44, 0x6a9bcc5f, 0x6490c156, 0x4ea1e269, 0x40aaef60, 0x52b7f87b, 0x5cbcf572, 0x6d5be05, 0x8deb30c, 0x1ac3a417, 0x14c8a91e, 0x3ef98a21, 0x30f28728, 0x22ef9033, 0x2ce49d3a, 0x963d06dd, 0x98360bd4, 0x8a2b1ccf, 0x842011c6, 0xae1132f9, 0xa01a3ff0, 0xb20728eb, 0xbc0c25e2, 0xe6656e95, 0xe86e639c, 0xfa737487, 0xf478798e, 0xde495ab1, 0xd04257b8, 0xc25f40a3, 0xcc544daa, 0x41f7daec, 0x4ffcd7e5, 0x5de1c0fe, 0x53eacdf7, 0x79dbeec8, 0x77d0e3c1, 0x65cdf4da, 0x6bc6f9d3, 0x31afb2a4, 0x3fa4bfad, 0x2db9a8b6, 0x23b2a5bf, 0x9838680, 0x7888b89, 0x15959c92, 0x1b9e919b, 0xa1470a7c, 0xaf4c0775, 0xbd51106e, 0xb35a1d67, 0x996b3e58, 0x97603351, 0x857d244a, 0x8b762943, 0xd11f6234, 0xdf146f3d, 0xcd097826, 0xc302752f, 0xe9335610, 0xe7385b19, 0xf5254c02, 0xfb2e410b, 0x9a8c61d7, 0x94876cde, 0x869a7bc5, 0x889176cc, 0xa2a055f3, 0xacab58fa, 0xbeb64fe1, 0xb0bd42e8, 0xead4099f, 0xe4df0496, 0xf6c2138d, 0xf8c91e84, 0xd2f83dbb, 0xdcf330b2, 0xceee27a9, 0xc0e52aa0, 0x7a3cb147, 0x7437bc4e, 0x662aab55, 0x6821a65c, 0x42108563, 0x4c1b886a, 0x5e069f71, 0x500d9278, 0xa64d90f, 0x46fd406, 0x1672c31d, 0x1879ce14, 0x3248ed2b, 0x3c43e022, 0x2e5ef739, 0x2055fa30, 0xec01b79a, 0xe20aba93, 0xf017ad88, 0xfe1ca081, 0xd42d83be, 0xda268eb7, 0xc83b99ac, 0xc63094a5, 0x9c59dfd2, 0x9252d2db, 0x804fc5c0, 0x8e44c8c9, 0xa475ebf6, 0xaa7ee6ff, 0xb863f1e4, 0xb668fced, 0xcb1670a, 0x2ba6a03, 0x10a77d18, 0x1eac7011, 0x349d532e, 0x3a965e27, 0x288b493c, 0x26804435, 0x7ce90f42, 0x72e2024b, 0x60ff1550, 0x6ef41859, 0x44c53b66, 0x4ace366f, 0x58d32174, 0x56d82c7d, 0x377a0ca1, 0x397101a8, 0x2b6c16b3, 0x25671bba, 0xf563885, 0x15d358c, 0x13402297, 0x1d4b2f9e, 0x472264e9, 0x492969e0, 0x5b347efb, 0x553f73f2, 0x7f0e50cd, 0x71055dc4, 0x63184adf, 0x6d1347d6, 0xd7cadc31, 0xd9c1d138, 0xcbdcc623, 0xc5d7cb2a, 0xefe6e815, 0xe1ede51c, 0xf3f0f207, 0xfdfbff0e, 0xa792b479, 0xa999b970, 0xbb84ae6b, 0xb58fa362, 0x9fbe805d, 0x91b58d54, 0x83a89a4f, 0x8da39746] + + /// Initialize AES with variant calculated out of key length: + /// - 16 bytes (AES-128) + /// - 24 bytes (AES-192) + /// - 32 bytes (AES-256) + /// + /// - parameter key: Key. Length of the key decides on AES variant. + /// - parameter iv: Initialization Vector (Optional for some blockMode values) + /// - parameter blockMode: Cipher mode of operation + /// - parameter padding: Padding method. .pkcs7, .noPadding, .zeroPadding, ... + /// + /// - throws: AES.Error + /// + /// - returns: Instance + public init(key: Array, blockMode: BlockMode, padding: Padding = .pkcs7) throws { + self.key = Key(bytes: key) + self.blockMode = blockMode + self.padding = padding + self.keySize = self.key.count + + // Validate key size + switch self.keySize * 8 { + case 128: + self.variant = .aes128 + case 192: + self.variant = .aes192 + case 256: + self.variant = .aes256 + default: + throw Error.invalidKeySize + } + + self.variantNb = self.variant.Nb + self.variantNk = self.variant.Nk + self.variantNr = self.variant.Nr + } + + internal func encrypt(block: ArraySlice) -> Array? { + if self.blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize { + return Array(block) + } + + let rounds = self.variantNr + let rk = self.expandedKey + + let b00 = UInt32(block[block.startIndex.advanced(by: 0)]) + let b01 = UInt32(block[block.startIndex.advanced(by: 1)]) << 8 + let b02 = UInt32(block[block.startIndex.advanced(by: 2)]) << 16 + let b03 = UInt32(block[block.startIndex.advanced(by: 3)]) << 24 + var b0 = b00 | b01 | b02 | b03 + + let b10 = UInt32(block[block.startIndex.advanced(by: 4)]) + let b11 = UInt32(block[block.startIndex.advanced(by: 5)]) << 8 + let b12 = UInt32(block[block.startIndex.advanced(by: 6)]) << 16 + let b13 = UInt32(block[block.startIndex.advanced(by: 7)]) << 24 + var b1 = b10 | b11 | b12 | b13 + + let b20 = UInt32(block[block.startIndex.advanced(by: 8)]) + let b21 = UInt32(block[block.startIndex.advanced(by: 9)]) << 8 + let b22 = UInt32(block[block.startIndex.advanced(by: 10)]) << 16 + let b23 = UInt32(block[block.startIndex.advanced(by: 11)]) << 24 + var b2 = b20 | b21 | b22 | b23 + + let b30 = UInt32(block[block.startIndex.advanced(by: 12)]) + let b31 = UInt32(block[block.startIndex.advanced(by: 13)]) << 8 + let b32 = UInt32(block[block.startIndex.advanced(by: 14)]) << 16 + let b33 = UInt32(block[block.startIndex.advanced(by: 15)]) << 24 + var b3 = b30 | b31 | b32 | b33 + + let tLength = 4 + let t = UnsafeMutablePointer.allocate(capacity: tLength) + t.initialize(repeating: 0, count: tLength) + defer { + t.deinitialize(count: tLength) + t.deallocate() + } + + for r in 0..> 8) & 0xff)] + let lb02 = AES.T2[Int((t[2] >> 16) & 0xff)] + let lb03 = AES.T3[Int(t[3] >> 24)] + b0 = lb00 ^ lb01 ^ lb02 ^ lb03 + + let lb10 = AES.T0[Int(t[1] & 0xff)] + let lb11 = AES.T1[Int((t[2] >> 8) & 0xff)] + let lb12 = AES.T2[Int((t[3] >> 16) & 0xff)] + let lb13 = AES.T3[Int(t[0] >> 24)] + b1 = lb10 ^ lb11 ^ lb12 ^ lb13 + + let lb20 = AES.T0[Int(t[2] & 0xff)] + let lb21 = AES.T1[Int((t[3] >> 8) & 0xff)] + let lb22 = AES.T2[Int((t[0] >> 16) & 0xff)] + let lb23 = AES.T3[Int(t[1] >> 24)] + b2 = lb20 ^ lb21 ^ lb22 ^ lb23 + + let lb30 = AES.T0[Int(t[3] & 0xff)] + let lb31 = AES.T1[Int((t[0] >> 8) & 0xff)] + let lb32 = AES.T2[Int((t[1] >> 16) & 0xff)] + let lb33 = AES.T3[Int(t[2] >> 24)] + b3 = lb30 ^ lb31 ^ lb32 ^ lb33 + } + + // last round + let r = rounds - 1 + + t[0] = b0 ^ rk[r][0] + t[1] = b1 ^ rk[r][1] + t[2] = b2 ^ rk[r][2] + t[3] = b3 ^ rk[r][3] + + // rounds + b0 = F1(t[0], t[1], t[2], t[3]) ^ rk[rounds][0] + b1 = F1(t[1], t[2], t[3], t[0]) ^ rk[rounds][1] + b2 = F1(t[2], t[3], t[0], t[1]) ^ rk[rounds][2] + b3 = F1(t[3], t[0], t[1], t[2]) ^ rk[rounds][3] + + let encrypted: Array = [ + UInt8(b0 & 0xff), UInt8((b0 >> 8) & 0xff), UInt8((b0 >> 16) & 0xff), UInt8((b0 >> 24) & 0xff), + UInt8(b1 & 0xff), UInt8((b1 >> 8) & 0xff), UInt8((b1 >> 16) & 0xff), UInt8((b1 >> 24) & 0xff), + UInt8(b2 & 0xff), UInt8((b2 >> 8) & 0xff), UInt8((b2 >> 16) & 0xff), UInt8((b2 >> 24) & 0xff), + UInt8(b3 & 0xff), UInt8((b3 >> 8) & 0xff), UInt8((b3 >> 16) & 0xff), UInt8((b3 >> 24) & 0xff) + ] + return encrypted + } + + internal func decrypt(block: ArraySlice) -> Array? { + if self.blockMode.options.contains(.paddingRequired) && block.count != AES.blockSize { + return Array(block) + } + + let rounds = self.variantNr + let rk = self.expandedKeyInv + + // Save miliseconds by not using `block.toUInt32Array()` + let b00 = UInt32(block[block.startIndex.advanced(by: 0)]) + let b01 = UInt32(block[block.startIndex.advanced(by: 1)]) << 8 + let b02 = UInt32(block[block.startIndex.advanced(by: 2)]) << 16 + let b03 = UInt32(block[block.startIndex.advanced(by: 3)]) << 24 + var b0 = b00 | b01 | b02 | b03 + + let b10 = UInt32(block[block.startIndex.advanced(by: 4)]) + let b11 = UInt32(block[block.startIndex.advanced(by: 5)]) << 8 + let b12 = UInt32(block[block.startIndex.advanced(by: 6)]) << 16 + let b13 = UInt32(block[block.startIndex.advanced(by: 7)]) << 24 + var b1 = b10 | b11 | b12 | b13 + + let b20 = UInt32(block[block.startIndex.advanced(by: 8)]) + let b21 = UInt32(block[block.startIndex.advanced(by: 9)]) << 8 + let b22 = UInt32(block[block.startIndex.advanced(by: 10)]) << 16 + let b23 = UInt32(block[block.startIndex.advanced(by: 11)]) << 24 + var b2 = b20 | b21 | b22 | b23 + + let b30 = UInt32(block[block.startIndex.advanced(by: 12)]) + let b31 = UInt32(block[block.startIndex.advanced(by: 13)]) << 8 + let b32 = UInt32(block[block.startIndex.advanced(by: 14)]) << 16 + let b33 = UInt32(block[block.startIndex.advanced(by: 15)]) << 24 + var b3 = b30 | b31 | b32 | b33 + + let tLength = 4 + let t = UnsafeMutablePointer.allocate(capacity: tLength) + t.initialize(repeating: 0, count: tLength) + defer { + t.deinitialize(count: tLength) + t.deallocate() + } + + for r in (2...rounds).reversed() { + t[0] = b0 ^ rk[r][0] + t[1] = b1 ^ rk[r][1] + t[2] = b2 ^ rk[r][2] + t[3] = b3 ^ rk[r][3] + + let b00 = AES.T0_INV[Int(t[0] & 0xff)] + let b01 = AES.T1_INV[Int((t[3] >> 8) & 0xff)] + let b02 = AES.T2_INV[Int((t[2] >> 16) & 0xff)] + let b03 = AES.T3_INV[Int(t[1] >> 24)] + b0 = b00 ^ b01 ^ b02 ^ b03 + + let b10 = AES.T0_INV[Int(t[1] & 0xff)] + let b11 = AES.T1_INV[Int((t[0] >> 8) & 0xff)] + let b12 = AES.T2_INV[Int((t[3] >> 16) & 0xff)] + let b13 = AES.T3_INV[Int(t[2] >> 24)] + b1 = b10 ^ b11 ^ b12 ^ b13 + + let b20 = AES.T0_INV[Int(t[2] & 0xff)] + let b21 = AES.T1_INV[Int((t[1] >> 8) & 0xff)] + let b22 = AES.T2_INV[Int((t[0] >> 16) & 0xff)] + let b23 = AES.T3_INV[Int(t[3] >> 24)] + b2 = b20 ^ b21 ^ b22 ^ b23 + + let b30 = AES.T0_INV[Int(t[3] & 0xff)] + let b31 = AES.T1_INV[Int((t[2] >> 8) & 0xff)] + let b32 = AES.T2_INV[Int((t[1] >> 16) & 0xff)] + let b33 = AES.T3_INV[Int(t[0] >> 24)] + b3 = b30 ^ b31 ^ b32 ^ b33 + } + + // last round + t[0] = b0 ^ rk[1][0] + t[1] = b1 ^ rk[1][1] + t[2] = b2 ^ rk[1][2] + t[3] = b3 ^ rk[1][3] + + // rounds + + let lb00 = self.sBoxInv[Int(B0(t[0]))] + let lb01 = (sBoxInv[Int(B1(t[3]))] << 8) + let lb02 = (sBoxInv[Int(B2(t[2]))] << 16) + let lb03 = (sBoxInv[Int(B3(t[1]))] << 24) + b0 = lb00 | lb01 | lb02 | lb03 ^ rk[0][0] + + let lb10 = self.sBoxInv[Int(B0(t[1]))] + let lb11 = (sBoxInv[Int(B1(t[0]))] << 8) + let lb12 = (sBoxInv[Int(B2(t[3]))] << 16) + let lb13 = (sBoxInv[Int(B3(t[2]))] << 24) + b1 = lb10 | lb11 | lb12 | lb13 ^ rk[0][1] + + let lb20 = self.sBoxInv[Int(B0(t[2]))] + let lb21 = (sBoxInv[Int(B1(t[1]))] << 8) + let lb22 = (sBoxInv[Int(B2(t[0]))] << 16) + let lb23 = (sBoxInv[Int(B3(t[3]))] << 24) + b2 = lb20 | lb21 | lb22 | lb23 ^ rk[0][2] + + let lb30 = self.sBoxInv[Int(B0(t[3]))] + let lb31 = (sBoxInv[Int(B1(t[2]))] << 8) + let lb32 = (sBoxInv[Int(B2(t[1]))] << 16) + let lb33 = (sBoxInv[Int(B3(t[0]))] << 24) + b3 = lb30 | lb31 | lb32 | lb33 ^ rk[0][3] + + let result: Array = [ + UInt8(b0 & 0xff), UInt8((b0 >> 8) & 0xff), UInt8((b0 >> 16) & 0xff), UInt8((b0 >> 24) & 0xff), + UInt8(b1 & 0xff), UInt8((b1 >> 8) & 0xff), UInt8((b1 >> 16) & 0xff), UInt8((b1 >> 24) & 0xff), + UInt8(b2 & 0xff), UInt8((b2 >> 8) & 0xff), UInt8((b2 >> 16) & 0xff), UInt8((b2 >> 24) & 0xff), + UInt8(b3 & 0xff), UInt8((b3 >> 8) & 0xff), UInt8((b3 >> 16) & 0xff), UInt8((b3 >> 24) & 0xff) + ] + return result + } +} + +private extension AES { + private func expandKeyInv(_ key: Key, variant: Variant) -> Array> { + let rounds = self.variantNr + var rk2: Array> = self.expandKey(key, variant: variant) + + for r in 1.. Array> { + func convertExpandedKey(_ expanded: Array) -> Array> { + expanded.batched(by: 4).map({ UInt32(bytes: $0.reversed()) }).batched(by: 4).map { Array($0) } + } + + /* + * Function used in the Key Expansion routine that takes a four-byte + * input word and applies an S-box to each of the four bytes to + * produce an output word. + */ + func subWord(_ word: Array) -> Array { + precondition(word.count == 4) + + var result = word + for i in 0..<4 { + result[i] = UInt8(self.sBox[Int(word[i])]) + } + return result + } + + @inline(__always) + func subWordInPlace(_ word: inout Array) { + precondition(word.count == 4) + word[0] = UInt8(self.sBox[Int(word[0])]) + word[1] = UInt8(self.sBox[Int(word[1])]) + word[2] = UInt8(self.sBox[Int(word[2])]) + word[3] = UInt8(self.sBox[Int(word[3])]) + } + + let wLength = self.variantNb * (self.variantNr + 1) * 4 + let w = UnsafeMutablePointer.allocate(capacity: wLength) + w.initialize(repeating: 0, count: wLength) + defer { + w.deinitialize(count: wLength) + w.deallocate() + } + + for i in 0.. + + for i in self.variantNk..(repeating: 0, count: 4) + + for wordIdx in 0..<4 { + tmp[wordIdx] = w[4 * (i - 1) + wordIdx] + } + if (i % self.variantNk) == 0 { + tmp = subWord(rotateLeft(UInt32(bytes: tmp), by: 8).bytes(totalBytes: 4)) + tmp[0] = tmp.first! ^ AES.Rcon[i / variantNk] + } else if self.variantNk > 6 && (i % self.variantNk) == 4 { + subWordInPlace(&tmp) + } + + // xor array of bytes + for wordIdx in 0..<4 { + w[4 * i + wordIdx] = w[4 * (i - variantNk) + wordIdx] ^ tmp[wordIdx] + } + } + return convertExpandedKey(Array(UnsafeBufferPointer(start: w, count: wLength))) + } + + @inline(__always) + private func B0(_ x: UInt32) -> UInt32 { + x & 0xff + } + + @inline(__always) + private func B1(_ x: UInt32) -> UInt32 { + (x >> 8) & 0xff + } + + @inline(__always) + private func B2(_ x: UInt32) -> UInt32 { + (x >> 16) & 0xff + } + + @inline(__always) + private func B3(_ x: UInt32) -> UInt32 { + (x >> 24) & 0xff + } + + @inline(__always) + private func F1(_ x0: UInt32, _ x1: UInt32, _ x2: UInt32, _ x3: UInt32) -> UInt32 { + var result: UInt32 = 0 + result |= UInt32(self.B1(AES.T0[Int(x0 & 255)])) + result |= UInt32(self.B1(AES.T0[Int((x1 >> 8) & 255)])) << 8 + result |= UInt32(self.B1(AES.T0[Int((x2 >> 16) & 255)])) << 16 + result |= UInt32(self.B1(AES.T0[Int(x3 >> 24)])) << 24 + return result + } + + private func calculateSBox() -> (sBox: Array, invSBox: Array) { + let sboxLength = 256 + let sbox = UnsafeMutablePointer.allocate(capacity: sboxLength) + let invsbox = UnsafeMutablePointer.allocate(capacity: sboxLength) + sbox.initialize(repeating: 0, count: sboxLength) + invsbox.initialize(repeating: 0, count: sboxLength) + defer { + sbox.deinitialize(count: sboxLength) + sbox.deallocate() + invsbox.deinitialize(count: sboxLength) + invsbox.deallocate() + } + + sbox[0] = 0x63 + + var p: UInt8 = 1, q: UInt8 = 1 + + repeat { + p = p ^ (UInt8(truncatingIfNeeded: Int(p) << 1) ^ ((p & 0x80) == 0x80 ? 0x1b : 0)) + q ^= q << 1 + q ^= q << 2 + q ^= q << 4 + q ^= (q & 0x80) == 0x80 ? 0x09 : 0 + + let s = 0x63 ^ q ^ rotateLeft(q, by: 1) ^ rotateLeft(q, by: 2) ^ rotateLeft(q, by: 3) ^ rotateLeft(q, by: 4) + + sbox[Int(p)] = UInt32(s) + invsbox[Int(s)] = UInt32(p) + } while p != 1 + + return (sBox: Array(UnsafeBufferPointer(start: sbox, count: sboxLength)), invSBox: Array(UnsafeBufferPointer(start: invsbox, count: sboxLength))) + } +} + +// MARK: Cipher + +extension AES: Cipher { + public func encrypt(_ bytes: ArraySlice) throws -> Array { + let chunks = bytes.batched(by: AES.blockSize) + + var oneTimeCryptor = try makeEncryptor() + var out = Array(reserveCapacity: bytes.count) + for chunk in chunks { + out += try oneTimeCryptor.update(withBytes: chunk, isLast: false) + } + // Padding may be added at the very end + out += try oneTimeCryptor.finish() + + if self.blockMode.options.contains(.paddingRequired) && (out.count % AES.blockSize != 0) { + throw Error.dataPaddingRequired + } + + return out + } + + public func decrypt(_ bytes: ArraySlice) throws -> Array { + if self.blockMode.options.contains(.paddingRequired) && (bytes.count % AES.blockSize != 0) { + throw Error.dataPaddingRequired + } + + var oneTimeCryptor = try makeDecryptor() + let chunks = bytes.batched(by: AES.blockSize) + if chunks.isEmpty { + throw Error.invalidData + } + + var out = Array(reserveCapacity: bytes.count) + + var lastIdx = chunks.startIndex + chunks.indices.formIndex(&lastIdx, offsetBy: chunks.count - 1) + + // To properly remove padding, `isLast` has to be known when called with the last chunk of ciphertext + // Last chunk of ciphertext may contains padded data so next call to update(..) won't be able to remove it + for idx in chunks.indices { + out += try oneTimeCryptor.update(withBytes: chunks[idx], isLast: idx == lastIdx) + } + return out + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Array+Extension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Array+Extension.swift new file mode 100644 index 0000000..a9c41d4 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Array+Extension.swift @@ -0,0 +1,148 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +extension Array { + init(reserveCapacity: Int) { + self = Array() + self.reserveCapacity(reserveCapacity) + } + + var slice: ArraySlice { + self[self.startIndex ..< self.endIndex] + } +} + +extension Array where Element == UInt8 { + public init(hex: String) { + self.init(reserveCapacity: hex.unicodeScalars.lazy.underestimatedCount) + var buffer: UInt8? + var skip = hex.hasPrefix("0x") ? 2 : 0 + for char in hex.unicodeScalars.lazy { + guard skip == 0 else { + skip -= 1 + continue + } + guard char.value >= 48 && char.value <= 102 else { + removeAll() + return + } + let v: UInt8 + let c: UInt8 = UInt8(char.value) + switch c { + case let c where c <= 57: + v = c - 48 + case let c where c >= 65 && c <= 70: + v = c - 55 + case let c where c >= 97: + v = c - 87 + default: + removeAll() + return + } + if let b = buffer { + append(b << 4 | v) + buffer = nil + } else { + buffer = v + } + } + if let b = buffer { + append(b) + } + } + + public func toHexString() -> String { + `lazy`.reduce("") { + var s = String($1, radix: 16) + if s.count == 1 { + s = "0" + s + } + return $0 + s + } + } +} + +extension Array where Element == UInt8 { + /// split in chunks with given chunk size + @available(*, deprecated) + public func chunks(size chunksize: Int) -> Array> { + var words = Array>() + words.reserveCapacity(count / chunksize) + for idx in stride(from: chunksize, through: count, by: chunksize) { + words.append(Array(self[idx - chunksize ..< idx])) // slow for large table + } + let remainder = suffix(count % chunksize) + if !remainder.isEmpty { + words.append(Array(remainder)) + } + return words + } + + public func md5() -> [Element] { + Digest.md5(self) + } + + public func sha1() -> [Element] { + Digest.sha1(self) + } + + public func sha224() -> [Element] { + Digest.sha224(self) + } + + public func sha256() -> [Element] { + Digest.sha256(self) + } + + public func sha384() -> [Element] { + Digest.sha384(self) + } + + public func sha512() -> [Element] { + Digest.sha512(self) + } + + public func sha2(_ variant: SHA2.Variant) -> [Element] { + Digest.sha2(self, variant: variant) + } + + public func sha3(_ variant: SHA3.Variant) -> [Element] { + Digest.sha3(self, variant: variant) + } + + public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { + Checksum.crc32(self, seed: seed, reflect: reflect) + } + + public func crc32c(seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { + Checksum.crc32c(self, seed: seed, reflect: reflect) + } + + public func crc16(seed: UInt16? = nil) -> UInt16 { + Checksum.crc16(self, seed: seed) + } + + public func encrypt(cipher: Cipher) throws -> [Element] { + try cipher.encrypt(self.slice) + } + + public func decrypt(cipher: Cipher) throws -> [Element] { + try cipher.decrypt(self.slice) + } + + public func authenticate(with authenticator: A) throws -> [Element] { + try authenticator.authenticate(self) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Authenticator.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Authenticator.swift new file mode 100644 index 0000000..90b534e --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Authenticator.swift @@ -0,0 +1,20 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +/// Message authentication code. +public protocol Authenticator { + /// Calculate Message Authentication Code (MAC) for message. + func authenticate(_ bytes: Array) throws -> Array +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BatchedCollection.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BatchedCollection.swift new file mode 100644 index 0000000..5438c10 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BatchedCollection.swift @@ -0,0 +1,63 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +struct BatchedCollectionIndex { + let range: Range +} + +extension BatchedCollectionIndex: Comparable { + static func == (lhs: BatchedCollectionIndex, rhs: BatchedCollectionIndex) -> Bool { + lhs.range.lowerBound == rhs.range.lowerBound + } + + static func < (lhs: BatchedCollectionIndex, rhs: BatchedCollectionIndex) -> Bool { + lhs.range.lowerBound < rhs.range.lowerBound + } +} + +protocol BatchedCollectionType: Collection { + associatedtype Base: Collection +} + +struct BatchedCollection: Collection { + let base: Base + let size: Int + typealias Index = BatchedCollectionIndex + private func nextBreak(after idx: Base.Index) -> Base.Index { + self.base.index(idx, offsetBy: self.size, limitedBy: self.base.endIndex) ?? self.base.endIndex + } + + var startIndex: Index { + Index(range: self.base.startIndex.. Index { + Index(range: idx.range.upperBound.. Base.SubSequence { + self.base[idx.range] + } +} + +extension Collection { + func batched(by size: Int) -> BatchedCollection { + BatchedCollection(base: self, size: size) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Bit.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Bit.swift new file mode 100644 index 0000000..8ad9558 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Bit.swift @@ -0,0 +1,25 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public enum Bit: Int { + case zero + case one +} + +extension Bit { + func inverted() -> Bit { + self == .zero ? .one : .zero + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockCipher.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockCipher.swift new file mode 100644 index 0000000..b07f035 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockCipher.swift @@ -0,0 +1,18 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +protocol BlockCipher: Cipher { + static var blockSize: Int { get } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockDecryptor.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockDecryptor.swift new file mode 100644 index 0000000..328169e --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockDecryptor.swift @@ -0,0 +1,85 @@ +// CryptoSwift +// +// Copyright (C) 2014-2018 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public class BlockDecryptor: Cryptor, Updatable { + private let blockSize: Int + private let padding: Padding + private var worker: CipherModeWorker + private var accumulated = Array() + + init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws { + self.blockSize = blockSize + self.padding = padding + self.worker = worker + } + + public func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array { + self.accumulated += bytes + + // If a worker (eg GCM) can combine ciphertext + tag + // we need to remove tag from the ciphertext. + if !isLast && self.accumulated.count < self.blockSize + self.worker.additionalBufferSize { + return [] + } + + let accumulatedWithoutSuffix: Array + if self.worker.additionalBufferSize > 0 { + // FIXME: how slow is that? + accumulatedWithoutSuffix = Array(self.accumulated.prefix(self.accumulated.count - self.worker.additionalBufferSize)) + } else { + accumulatedWithoutSuffix = self.accumulated + } + + var processedBytesCount = 0 + var plaintext = Array(reserveCapacity: accumulatedWithoutSuffix.count) + // Processing in a block-size manner. It's good for block modes, but bad for stream modes. + for var chunk in accumulatedWithoutSuffix.batched(by: self.blockSize) { + if isLast || (accumulatedWithoutSuffix.count - processedBytesCount) >= blockSize { + let isLastChunk = processedBytesCount + chunk.count == accumulatedWithoutSuffix.count + + if isLast, isLastChunk, var finalizingWorker = worker as? FinalizingDecryptModeWorker { + chunk = try finalizingWorker.willDecryptLast(bytes: chunk + accumulated.suffix(worker.additionalBufferSize)) // tag size + } + + if !chunk.isEmpty { + plaintext += worker.decrypt(block: chunk) + } + + if isLast, isLastChunk, var finalizingWorker = worker as? FinalizingDecryptModeWorker { + plaintext = Array(try finalizingWorker.didDecryptLast(bytes: plaintext.slice)) + } + + processedBytesCount += chunk.count + } + } + accumulated.removeFirst(processedBytesCount) // super-slow + + if isLast { + plaintext = self.padding.remove(from: plaintext, blockSize: self.blockSize) + } + + return plaintext + } + + public func seek(to position: Int) throws { + guard var worker = self.worker as? SeekableModeWorker else { + fatalError("Not supported") + } + + try worker.seek(to: position) + self.worker = worker + + accumulated = [] + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockEncryptor.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockEncryptor.swift new file mode 100644 index 0000000..1e24499 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockEncryptor.swift @@ -0,0 +1,58 @@ +// CryptoSwift +// +// Copyright (C) 2014-2018 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// +final class BlockEncryptor: Cryptor, Updatable { + private let blockSize: Int + private var worker: CipherModeWorker + private let padding: Padding + // Accumulated bytes. Not all processed bytes. + private var accumulated = Array(reserveCapacity: 16) + + private var lastBlockRemainder = 0 + + init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws { + self.blockSize = blockSize + self.padding = padding + self.worker = worker + } + + // MARK: Updatable + + public func update(withBytes bytes: ArraySlice, isLast: Bool) throws -> Array { + self.accumulated += bytes + + if isLast { + self.accumulated = self.padding.add(to: self.accumulated, blockSize: self.blockSize) + } + + var encrypted = Array(reserveCapacity: accumulated.count) + for chunk in self.accumulated.batched(by: self.blockSize) { + if isLast || chunk.count == self.blockSize { + encrypted += self.worker.encrypt(block: chunk) + } + } + + // Stream encrypts all, so it removes all elements + self.accumulated.removeFirst(encrypted.count) + + if var finalizingWorker = worker as? FinalizingEncryptModeWorker, isLast == true { + encrypted = Array(try finalizingWorker.finalize(encrypt: encrypted.slice)) + } + + return encrypted + } + + func seek(to: Int) throws { + fatalError("Not supported") + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockMode.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockMode.swift new file mode 100644 index 0000000..de613c5 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockMode.swift @@ -0,0 +1,24 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public typealias CipherOperationOnBlock = (_ block: ArraySlice) -> Array? + +public protocol BlockMode { + var options: BlockModeOption { get } + //TODO: doesn't have to be public + func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker +} + +typealias StreamMode = BlockMode diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockModeOptions.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockModeOptions.swift new file mode 100644 index 0000000..3f2f7bb --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/BlockModeOptions.swift @@ -0,0 +1,27 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public struct BlockModeOption: OptionSet { + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + static let none = BlockModeOption(rawValue: 1 << 0) + static let initializationVectorRequired = BlockModeOption(rawValue: 1 << 1) + static let paddingRequired = BlockModeOption(rawValue: 1 << 2) + static let useEncryptToDecrypt = BlockModeOption(rawValue: 1 << 3) +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CBC.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CBC.swift new file mode 100644 index 0000000..e9043fc --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CBC.swift @@ -0,0 +1,70 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// Cipher-block chaining (CBC) +// + +public struct CBC: BlockMode { + public enum Error: Swift.Error { + /// Invalid IV + case invalidInitializationVector + } + + public let options: BlockModeOption = [.initializationVectorRequired, .paddingRequired] + private let iv: Array + + public init(iv: Array) { + self.iv = iv + } + + public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { + if self.iv.count != blockSize { + throw Error.invalidInitializationVector + } + + return CBCModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation) + } +} + +struct CBCModeWorker: BlockModeWorker { + let cipherOperation: CipherOperationOnBlock + var blockSize: Int + let additionalBufferSize: Int = 0 + private let iv: ArraySlice + private var prev: ArraySlice? + + init(blockSize: Int, iv: ArraySlice, cipherOperation: @escaping CipherOperationOnBlock) { + self.blockSize = blockSize + self.iv = iv + self.cipherOperation = cipherOperation + } + + mutating func encrypt(block plaintext: ArraySlice) -> Array { + guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else { + return Array(plaintext) + } + self.prev = ciphertext.slice + return ciphertext + } + + mutating func decrypt(block ciphertext: ArraySlice) -> Array { + guard let plaintext = cipherOperation(ciphertext) else { + return Array(ciphertext) + } + let result: Array = xor(prev ?? self.iv, plaintext) + self.prev = ciphertext + return result + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CCM.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CCM.swift new file mode 100644 index 0000000..1a1a75c --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CCM.swift @@ -0,0 +1,357 @@ +//// CryptoSwift +// +// Copyright (C) 2014-2018 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// CCM mode combines the well known CBC-MAC with the well known counter mode of encryption. +// https://tools.ietf.org/html/rfc3610 +// https://csrc.nist.gov/publications/detail/sp/800-38c/final + +#if canImport(Darwin) + import Darwin +#else + import Glibc +#endif + +/// Counter with Cipher Block Chaining-Message Authentication Code +public struct CCM: StreamMode { + public enum Error: Swift.Error { + /// Invalid IV + case invalidInitializationVector + case invalidParameter + case fail + } + + public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt] + private let nonce: Array + private let additionalAuthenticatedData: Array? + private let tagLength: Int + private let messageLength: Int // total message length. need to know in advance + + // `authenticationTag` nil for encryption, known tag for decryption + /// For encryption, the value is set at the end of the encryption. + /// For decryption, this is a known Tag to validate against. + public var authenticationTag: Array? + + /// Initialize CCM + /// + /// - Parameters: + /// - iv: Initialization vector. Nonce. Valid length between 7 and 13 bytes. + /// - tagLength: Authentication tag length, in bytes. Value of {4, 6, 8, 10, 12, 14, 16}. + /// - messageLength: Plaintext message length (excluding tag if attached). Length have to be provided in advance. + /// - additionalAuthenticatedData: Additional authenticated data. + public init(iv: Array, tagLength: Int, messageLength: Int, additionalAuthenticatedData: Array? = nil) { + self.nonce = iv + self.tagLength = tagLength + self.additionalAuthenticatedData = additionalAuthenticatedData + self.messageLength = messageLength // - tagLength + } + + /// Initialize CCM + /// + /// - Parameters: + /// - iv: Initialization vector. Nonce. Valid length between 7 and 13 bytes. + /// - tagLength: Authentication tag length, in bytes. Value of {4, 6, 8, 10, 12, 14, 16}. + /// - messageLength: Plaintext message length (excluding tag if attached). Length have to be provided in advance. + /// - authenticationTag: Authentication Tag value if not concatenated to ciphertext. + /// - additionalAuthenticatedData: Additional authenticated data. + public init(iv: Array, tagLength: Int, messageLength: Int, authenticationTag: Array, additionalAuthenticatedData: Array? = nil) { + self.init(iv: iv, tagLength: tagLength, messageLength: messageLength, additionalAuthenticatedData: additionalAuthenticatedData) + self.authenticationTag = authenticationTag + } + + public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { + if self.nonce.isEmpty { + throw Error.invalidInitializationVector + } + + return CCMModeWorker(blockSize: blockSize, nonce: self.nonce.slice, messageLength: self.messageLength, additionalAuthenticatedData: self.additionalAuthenticatedData, tagLength: self.tagLength, cipherOperation: cipherOperation) + } +} + +class CCMModeWorker: StreamModeWorker, SeekableModeWorker, CounterModeWorker, FinalizingEncryptModeWorker, FinalizingDecryptModeWorker { + typealias Counter = Int + var counter = 0 + + let cipherOperation: CipherOperationOnBlock + let blockSize: Int + private let tagLength: Int + private let messageLength: Int // total message length. need to know in advance + private let q: UInt8 + + let additionalBufferSize: Int + private var keystreamPosIdx = 0 + private let nonce: Array + private var last_y: ArraySlice = [] + private var keystream: Array = [] + // Known Tag used to validate during decryption + private var expectedTag: Array? + + public enum Error: Swift.Error { + case invalidParameter + } + + init(blockSize: Int, nonce: ArraySlice, messageLength: Int, additionalAuthenticatedData: [UInt8]?, expectedTag: Array? = nil, tagLength: Int, cipherOperation: @escaping CipherOperationOnBlock) { + self.blockSize = 16 // CCM is defined for 128 block size + self.tagLength = tagLength + self.additionalBufferSize = tagLength + self.messageLength = messageLength + self.expectedTag = expectedTag + self.cipherOperation = cipherOperation + self.nonce = Array(nonce) + self.q = UInt8(15 - nonce.count) // n = 15-q + + let hasAssociatedData = additionalAuthenticatedData != nil && !additionalAuthenticatedData!.isEmpty + self.processControlInformation(nonce: self.nonce, tagLength: tagLength, hasAssociatedData: hasAssociatedData) + + if let aad = additionalAuthenticatedData, hasAssociatedData { + self.process(aad: aad) + } + } + + // For the very first time setup new IV (aka y0) from the block0 + private func processControlInformation(nonce: [UInt8], tagLength: Int, hasAssociatedData: Bool) { + let block0 = try! format(nonce: nonce, Q: UInt32(self.messageLength), q: self.q, t: UInt8(tagLength), hasAssociatedData: hasAssociatedData).slice + let y0 = self.cipherOperation(block0)!.slice + self.last_y = y0 + } + + private func process(aad: [UInt8]) { + let encodedAAD = format(aad: aad) + + for block_i in encodedAAD.batched(by: 16) { + let y_i = self.cipherOperation(xor(block_i, self.last_y))!.slice + self.last_y = y_i + } + } + + private func S(i: Int) throws -> [UInt8] { + let ctr = try format(counter: i, nonce: nonce, q: q) + return self.cipherOperation(ctr.slice)! + } + + func seek(to position: Int) throws { + self.counter = position + self.keystream = try self.S(i: position) + let offset = position % self.blockSize + self.keystreamPosIdx = offset + } + + func encrypt(block plaintext: ArraySlice) -> Array { + var result = Array(reserveCapacity: plaintext.count) + + var processed = 0 + while processed < plaintext.count { + // Need a full block here to update keystream and do CBC + if self.keystream.isEmpty || self.keystreamPosIdx == self.blockSize { + // y[i], where i is the counter. Can encrypt 1 block at a time + self.counter += 1 + guard let S = try? S(i: counter) else { return Array(plaintext) } + let plaintextP = addPadding(Array(plaintext), blockSize: blockSize) + guard let y = cipherOperation(xor(last_y, plaintextP)) else { return Array(plaintext) } + self.last_y = y.slice + + self.keystream = S + self.keystreamPosIdx = 0 + } + + let xored: Array = xor(plaintext[plaintext.startIndex.advanced(by: processed)...], keystream[keystreamPosIdx...]) + keystreamPosIdx += xored.count + processed += xored.count + result += xored + } + return result + } + + func finalize(encrypt ciphertext: ArraySlice) throws -> ArraySlice { + // concatenate T at the end + guard let S0 = try? S(i: 0) else { return ciphertext } + + let computedTag = xor(last_y.prefix(self.tagLength), S0) as ArraySlice + return ciphertext + computedTag + } + + // Decryption is stream + // CBC is block + private var accumulatedPlaintext: [UInt8] = [] + + func decrypt(block ciphertext: ArraySlice) -> Array { + var output = Array(reserveCapacity: ciphertext.count) + + do { + var currentCounter = self.counter + var processed = 0 + while processed < ciphertext.count { + // Need a full block here to update keystream and do CBC + // New keystream for a new block + if self.keystream.isEmpty || self.keystreamPosIdx == self.blockSize { + currentCounter += 1 + guard let S = try? S(i: currentCounter) else { return Array(ciphertext) } + self.keystream = S + self.keystreamPosIdx = 0 + } + + let xored: Array = xor(ciphertext[ciphertext.startIndex.advanced(by: processed)...], keystream[keystreamPosIdx...]) // plaintext + keystreamPosIdx += xored.count + processed += xored.count + output += xored + self.counter = currentCounter + } + } + + // Accumulate plaintext for the MAC calculations at the end. + // It would be good to process it together though, here. + self.accumulatedPlaintext += output + + // Shouldn't return plaintext until validate tag. + // With incremental update, can't validate tag until all block are processed. + return output + } + + func finalize(decrypt plaintext: ArraySlice) throws -> ArraySlice { + // concatenate T at the end + let computedTag = Array(last_y.prefix(self.tagLength)) + guard let expectedTag = self.expectedTag, expectedTag == computedTag else { + throw CCM.Error.fail + } + + return plaintext + } + + @discardableResult + func willDecryptLast(bytes ciphertext: ArraySlice) throws -> ArraySlice { + // get tag of additionalBufferSize size + // `ciphertext` contains at least additionalBufferSize bytes + // overwrite expectedTag property used later for verification + guard let S0 = try? S(i: 0) else { return ciphertext } + self.expectedTag = xor(ciphertext.suffix(self.tagLength), S0) as [UInt8] + return ciphertext[ciphertext.startIndex..) throws -> ArraySlice { + + // Calculate Tag, from the last CBC block, for accumulated plaintext. + var processed = 0 + for block in self.accumulatedPlaintext.batched(by: self.blockSize) { + let blockP = addPadding(Array(block), blockSize: blockSize) + guard let y = cipherOperation(xor(last_y, blockP)) else { return plaintext } + self.last_y = y.slice + processed += block.count + } + self.accumulatedPlaintext.removeFirst(processed) + return plaintext + } +} + +// Q - octet length of P +// q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8} +// t - octet length of T (MAC length). An element of {4,6,8,10,12,14,16} +private func format(nonce N: [UInt8], Q: UInt32, q: UInt8, t: UInt8, hasAssociatedData: Bool) throws -> [UInt8] { + var flags0: UInt8 = 0 + + if hasAssociatedData { + // 7 bit + flags0 |= (1 << 6) + } + + // 6,5,4 bit is t in 3 bits + flags0 |= (((t - 2) / 2) & 0x07) << 3 + + // 3,2,1 bit is q in 3 bits + flags0 |= ((q - 1) & 0x07) << 0 + + var block0: [UInt8] = Array(repeating: 0, count: 16) + block0[0] = flags0 + + // N in 1...(15-q) octets, n = 15-q + // n is an element of {7,8,9,10,11,12,13} + let n = 15 - Int(q) + guard (n + Int(q)) == 15 else { + // n+q == 15 + throw CCMModeWorker.Error.invalidParameter + } + block0[1...n] = N[0...(n - 1)] + + // Q in (16-q)...15 octets + block0[(16 - Int(q))...15] = Q.bytes(totalBytes: Int(q)).slice + + return block0 +} + +/// Formatting of the Counter Blocks. Ctr[i] +/// The counter generation function. +/// Q - octet length of P +/// q - octet length of Q. Maximum length (in octets) of payload. An element of {2,3,4,5,6,7,8} +private func format(counter i: Int, nonce N: [UInt8], q: UInt8) throws -> [UInt8] { + var flags0: UInt8 = 0 + + // bit 8,7 is Reserved + // bit 4,5,6 shall be set to 0 + // 3,2,1 bit is q in 3 bits + flags0 |= ((q - 1) & 0x07) << 0 + + var block = Array(repeating: 0, count: 16) // block[0] + block[0] = flags0 + + // N in 1...(15-q) octets, n = 15-q + // n is an element of {7,8,9,10,11,12,13} + let n = 15 - Int(q) + guard (n + Int(q)) == 15 else { + // n+q == 15 + throw CCMModeWorker.Error.invalidParameter + } + block[1...n] = N[0...(n - 1)] + + // [i]8q in (16-q)...15 octets + block[(16 - Int(q))...15] = i.bytes(totalBytes: Int(q)).slice + + return block +} + +/// Resulting can be partitioned into 16-octet blocks +private func format(aad: [UInt8]) -> [UInt8] { + let a = aad.count + + switch Double(a) { + case 0..<65280: // 2^16-2^8 + // [a]16 + return addPadding(a.bytes(totalBytes: 2) + aad, blockSize: 16) + case 65280..<4_294_967_296: // 2^32 + // [a]32 + return addPadding([0xFF, 0xFE] + a.bytes(totalBytes: 4) + aad, blockSize: 16) + case 4_294_967_296.., blockSize: Int) -> Array { + if bytes.isEmpty { + return Array(repeating: 0, count: blockSize) + } + + let remainder = bytes.count % blockSize + if remainder == 0 { + return bytes + } + + let paddingCount = blockSize - remainder + if paddingCount > 0 { + return bytes + Array(repeating: 0, count: paddingCount) + } + return bytes +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CFB.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CFB.swift new file mode 100644 index 0000000..28e6ae5 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CFB.swift @@ -0,0 +1,70 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// Cipher feedback (CFB) +// + +public struct CFB: BlockMode { + public enum Error: Swift.Error { + /// Invalid IV + case invalidInitializationVector + } + + public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt] + private let iv: Array + + public init(iv: Array) { + self.iv = iv + } + + public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { + if self.iv.count != blockSize { + throw Error.invalidInitializationVector + } + + return CFBModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation) + } +} + +struct CFBModeWorker: BlockModeWorker { + let cipherOperation: CipherOperationOnBlock + let blockSize: Int + let additionalBufferSize: Int = 0 + private let iv: ArraySlice + private var prev: ArraySlice? + + init(blockSize: Int, iv: ArraySlice, cipherOperation: @escaping CipherOperationOnBlock) { + self.blockSize = blockSize + self.iv = iv + self.cipherOperation = cipherOperation + } + + mutating func encrypt(block plaintext: ArraySlice) -> Array { + guard let ciphertext = cipherOperation(prev ?? iv) else { + return Array(plaintext) + } + self.prev = xor(plaintext, ciphertext.slice) + return Array(self.prev ?? []) + } + + mutating func decrypt(block ciphertext: ArraySlice) -> Array { + guard let plaintext = cipherOperation(prev ?? iv) else { + return Array(ciphertext) + } + let result: Array = xor(plaintext, ciphertext) + prev = ciphertext + return result + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CTR.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CTR.swift new file mode 100644 index 0000000..8c9e35d --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/CTR.swift @@ -0,0 +1,134 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// Counter (CTR) + +public struct CTR: StreamMode { + public enum Error: Swift.Error { + /// Invalid IV + case invalidInitializationVector + } + + public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt] + private let iv: Array + private let counter: Int + + public init(iv: Array, counter: Int = 0) { + self.iv = iv + self.counter = counter + } + + public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { + if self.iv.count != blockSize { + throw Error.invalidInitializationVector + } + + return CTRModeWorker(blockSize: blockSize, iv: self.iv.slice, counter: self.counter, cipherOperation: cipherOperation) + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +struct CTRModeWorker: StreamModeWorker, SeekableModeWorker, CounterModeWorker { + typealias Counter = CTRCounter + + final class CTRCounter { + private let constPrefix: Array + private var value: UInt64 + //TODO: make it an updatable value, computing is too slow + var bytes: Array { + self.constPrefix + self.value.bytes() + } + + init(_ initialValue: Array) { + let halfIndex = initialValue.startIndex.advanced(by: initialValue.count / 2) + self.constPrefix = Array(initialValue[initialValue.startIndex.., startAt index: Int) { + self.init(buildCounterValue(nonce, counter: UInt64(index))) + } + + static func += (lhs: CTRCounter, rhs: Int) { + lhs.value += UInt64(rhs) + } + } + + let cipherOperation: CipherOperationOnBlock + let additionalBufferSize: Int = 0 + let iv: Array + var counter: CTRCounter + + private let blockSize: Int + + // The same keystream is used for the block length plaintext + // As new data is added, keystream suffix is used to xor operation. + private var keystream: Array + private var keystreamPosIdx = 0 + + init(blockSize: Int, iv: ArraySlice, counter: Int, cipherOperation: @escaping CipherOperationOnBlock) { + self.cipherOperation = cipherOperation + self.blockSize = blockSize + self.iv = Array(iv) + + // the first keystream is calculated from the nonce = initial value of counter + self.counter = CTRCounter(nonce: Array(iv), startAt: counter) + self.keystream = Array(cipherOperation(self.counter.bytes.slice)!) + } + + mutating func seek(to position: Int) throws { + let offset = position % self.blockSize + self.counter = CTRCounter(nonce: self.iv, startAt: position / self.blockSize) + self.keystream = Array(self.cipherOperation(self.counter.bytes.slice)!) + self.keystreamPosIdx = offset + } + + // plaintext is at most blockSize long + mutating func encrypt(block plaintext: ArraySlice) -> Array { + var result = Array(reserveCapacity: plaintext.count) + + var processed = 0 + while processed < plaintext.count { + // Update keystream + if self.keystreamPosIdx == self.blockSize { + self.counter += 1 + self.keystream = Array(self.cipherOperation(self.counter.bytes.slice)!) + self.keystreamPosIdx = 0 + } + + let xored: Array = xor(plaintext[plaintext.startIndex.advanced(by: processed)...], keystream[keystreamPosIdx...]) + keystreamPosIdx += xored.count + processed += xored.count + result += xored + } + + return result + } + + mutating func decrypt(block ciphertext: ArraySlice) -> Array { + self.encrypt(block: ciphertext) + } +} + +private func buildCounterValue(_ iv: Array, counter: UInt64) -> Array { + let noncePartLen = iv.count / 2 + let noncePrefix = iv[iv.startIndex.. +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public protocol CipherModeWorker { + var cipherOperation: CipherOperationOnBlock { get } + + // Additional space needed when incrementally process data + // eg. for GCM combined mode + var additionalBufferSize: Int { get } + + mutating func encrypt(block plaintext: ArraySlice) -> Array + mutating func decrypt(block ciphertext: ArraySlice) -> Array +} + +/// Block workers use `BlockEncryptor` +public protocol BlockModeWorker: CipherModeWorker { + var blockSize: Int { get } +} + +public protocol CounterModeWorker: CipherModeWorker { + associatedtype Counter + var counter: Counter { get set } +} + +public protocol SeekableModeWorker: CipherModeWorker { + mutating func seek(to position: Int) throws +} + +/// Stream workers use `StreamEncryptor` +public protocol StreamModeWorker: CipherModeWorker { +} + +public protocol FinalizingEncryptModeWorker: CipherModeWorker { + // Any final calculations, eg. calculate tag + // Called after the last block is encrypted + mutating func finalize(encrypt ciphertext: ArraySlice) throws -> ArraySlice +} + +public protocol FinalizingDecryptModeWorker: CipherModeWorker { + // Called before decryption, hence input is ciphertext. + // ciphertext is either a last block, or a tag (for stream workers) + @discardableResult + mutating func willDecryptLast(bytes ciphertext: ArraySlice) throws -> ArraySlice + // Called after decryption, hence input is ciphertext + mutating func didDecryptLast(bytes plaintext: ArraySlice) throws -> ArraySlice + // Any final calculations, eg. calculate tag + // Called after the last block is encrypted + mutating func finalize(decrypt plaintext: ArraySlice) throws -> ArraySlice +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/ECB.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/ECB.swift new file mode 100644 index 0000000..3559963 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/ECB.swift @@ -0,0 +1,51 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// Electronic codebook (ECB) +// + +public struct ECB: BlockMode { + public let options: BlockModeOption = .paddingRequired + + public init() { + } + + public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { + ECBModeWorker(blockSize: blockSize, cipherOperation: cipherOperation) + } +} + +struct ECBModeWorker: BlockModeWorker { + typealias Element = Array + let cipherOperation: CipherOperationOnBlock + let blockSize: Int + let additionalBufferSize: Int = 0 + + init(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) { + self.blockSize = blockSize + self.cipherOperation = cipherOperation + } + + mutating func encrypt(block plaintext: ArraySlice) -> Array { + guard let ciphertext = cipherOperation(plaintext) else { + return Array(plaintext) + } + return ciphertext + } + + mutating func decrypt(block ciphertext: ArraySlice) -> Array { + self.encrypt(block: ciphertext) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/GCM.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/GCM.swift new file mode 100644 index 0000000..64af630 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/GCM.swift @@ -0,0 +1,370 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// Galois/Counter Mode (GCM) +// https://csrc.nist.gov/publications/detail/sp/800-38d/final +// ref: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.694.695&rep=rep1&type=pdf +// + +public final class GCM: BlockMode { + public enum Mode { + /// In combined mode, the authentication tag is directly appended to the encrypted message. This is usually what you want. + case combined + /// Some applications may need to store the authentication tag and the encrypted message at different locations. + case detached + } + + public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt] + + public enum Error: Swift.Error { + /// Invalid IV + case invalidInitializationVector + /// Special symbol FAIL that indicates that the inputs are not authentic. + case fail + } + + private let iv: Array + private let additionalAuthenticatedData: Array? + private let mode: Mode + + /// Length of authentication tag, in bytes. + /// For encryption, the value is given as init parameter. + /// For decryption, the lenght of given authentication tag is used. + private let tagLength: Int + + // `authenticationTag` nil for encryption, known tag for decryption + /// For encryption, the value is set at the end of the encryption. + /// For decryption, this is a known Tag to validate against. + public var authenticationTag: Array? + + // encrypt + /// Possible tag lengths: 4,8,12,13,14,15,16 + public init(iv: Array, additionalAuthenticatedData: Array? = nil, tagLength: Int = 16, mode: Mode = .detached) { + self.iv = iv + self.additionalAuthenticatedData = additionalAuthenticatedData + self.mode = mode + self.tagLength = tagLength + } + + // decrypt + public convenience init(iv: Array, authenticationTag: Array, additionalAuthenticatedData: Array? = nil, mode: Mode = .detached) { + self.init(iv: iv, additionalAuthenticatedData: additionalAuthenticatedData, tagLength: authenticationTag.count, mode: mode) + self.authenticationTag = authenticationTag + } + + public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { + if self.iv.isEmpty { + throw Error.invalidInitializationVector + } + + let worker = GCMModeWorker(iv: iv.slice, aad: self.additionalAuthenticatedData?.slice, expectedTag: self.authenticationTag, tagLength: self.tagLength, mode: self.mode, cipherOperation: cipherOperation) + worker.didCalculateTag = { [weak self] tag in + self?.authenticationTag = tag + } + return worker + } +} + +// MARK: - Worker + +final class GCMModeWorker: BlockModeWorker, FinalizingEncryptModeWorker, FinalizingDecryptModeWorker { + let cipherOperation: CipherOperationOnBlock + + // Callback called when authenticationTag is ready + var didCalculateTag: ((Array) -> Void)? + + private let tagLength: Int + // GCM nonce is 96-bits by default. It's the most effective length for the IV + private static let nonceSize = 12 + + // GCM is designed for 128-bit ciphers like AES (but not really for Blowfish). 64-bit mode is not implemented. + let blockSize = 16 // 128 bit + let additionalBufferSize: Int + private let iv: ArraySlice + private let mode: GCM.Mode + private var counter: UInt128 + private let eky0: UInt128 // move to GF? + private let h: UInt128 + + // Additional authenticated data + private let aad: ArraySlice? + // Known Tag used to validate during decryption + private var expectedTag: Array? + + // Note: need new worker to reset instance + // Use empty aad if not specified. AAD is optional. + private lazy var gf: GF = { + if let aad = aad { + return GF(aad: Array(aad), h: h, blockSize: blockSize) + } + return GF(aad: [UInt8](), h: h, blockSize: blockSize) + }() + + init(iv: ArraySlice, aad: ArraySlice? = nil, expectedTag: Array? = nil, tagLength: Int, mode: GCM.Mode, cipherOperation: @escaping CipherOperationOnBlock) { + self.cipherOperation = cipherOperation + self.iv = iv + self.mode = mode + self.aad = aad + self.expectedTag = expectedTag + self.tagLength = tagLength + self.h = UInt128(cipherOperation(Array(repeating: 0, count: self.blockSize).slice)!) // empty block + + if mode == .combined { + self.additionalBufferSize = tagLength + } else { + self.additionalBufferSize = 0 + } + + // Assume nonce is 12 bytes long, otherwise initial counter would be calulated from GHASH + // counter = GF.ghash(aad: [UInt8](), ciphertext: nonce) + if iv.count == GCMModeWorker.nonceSize { + self.counter = makeCounter(nonce: Array(self.iv)) + } else { + self.counter = GF.ghash(h: self.h, aad: [UInt8](), ciphertext: Array(iv), blockSize: self.blockSize) + } + + // Set constants + self.eky0 = UInt128(cipherOperation(self.counter.bytes.slice)!) + } + + func encrypt(block plaintext: ArraySlice) -> Array { + self.counter = incrementCounter(self.counter) + + guard let ekyN = cipherOperation(counter.bytes.slice) else { + return Array(plaintext) + } + + // plaintext block ^ ek1 + let ciphertext = xor(plaintext, ekyN) as Array + + // update ghash incrementally + gf.ghashUpdate(block: ciphertext) + + return Array(ciphertext) + } + + func finalize(encrypt ciphertext: ArraySlice) throws -> ArraySlice { + // Calculate MAC tag. + let ghash = self.gf.ghashFinish() + let tag = Array((ghash ^ self.eky0).bytes.prefix(self.tagLength)) + + // Notify handler + self.didCalculateTag?(tag) + + switch self.mode { + case .combined: + return (ciphertext + tag).slice + case .detached: + return ciphertext + } + } + + func decrypt(block ciphertext: ArraySlice) -> Array { + self.counter = incrementCounter(self.counter) + + // update ghash incrementally + self.gf.ghashUpdate(block: Array(ciphertext)) + + guard let ekN = cipherOperation(counter.bytes.slice) else { + return Array(ciphertext) + } + + // ciphertext block ^ ek1 + let plaintext = xor(ciphertext, ekN) as Array + return plaintext + } + + // The authenticated decryption operation has five inputs: K, IV , C, A, and T. It has only a single + // output, either the plaintext value P or a special symbol FAIL that indicates that the inputs are not + // authentic. + @discardableResult + func willDecryptLast(bytes ciphertext: ArraySlice) throws -> ArraySlice { + // Validate tag + switch self.mode { + case .combined: + // overwrite expectedTag property used later for verification + self.expectedTag = Array(ciphertext.suffix(self.tagLength)) + return ciphertext[ciphertext.startIndex..) throws -> ArraySlice { + // Calculate MAC tag. + let ghash = self.gf.ghashFinish() + let computedTag = Array((ghash ^ self.eky0).bytes.prefix(self.tagLength)) + + // Validate tag + guard let expectedTag = self.expectedTag, computedTag == expectedTag else { + throw GCM.Error.fail + } + + return plaintext + } + + func finalize(decrypt plaintext: ArraySlice) throws -> ArraySlice { + // do nothing + plaintext + } +} + +// MARK: - Local utils + +private func makeCounter(nonce: Array) -> UInt128 { + UInt128(nonce + [0, 0, 0, 1]) +} + +// Successive counter values are generated using the function incr(), which treats the rightmost 32 +// bits of its argument as a nonnegative integer with the least significant bit on the right +private func incrementCounter(_ counter: UInt128) -> UInt128 { + let b = counter.i.b + 1 + let a = (b == 0 ? counter.i.a + 1 : counter.i.a) + return UInt128((a, b)) +} + +// If data is not a multiple of block size bytes long then the remainder is zero padded +// Note: It's similar to ZeroPadding, but it's not the same. +private func addPadding(_ bytes: Array, blockSize: Int) -> Array { + if bytes.isEmpty { + return Array(repeating: 0, count: blockSize) + } + + let remainder = bytes.count % blockSize + if remainder == 0 { + return bytes + } + + let paddingCount = blockSize - remainder + if paddingCount > 0 { + return bytes + Array(repeating: 0, count: paddingCount) + } + return bytes +} + +// MARK: - GF + +/// The Field GF(2^128) +private final class GF { + static let r = UInt128(a: 0xE100000000000000, b: 0) + + let blockSize: Int + let h: UInt128 + + // AAD won't change + let aadLength: Int + + // Updated for every consumed block + var ciphertextLength: Int + + // Start with 0 + var x: UInt128 + + init(aad: [UInt8], h: UInt128, blockSize: Int) { + self.blockSize = blockSize + self.aadLength = aad.count + self.ciphertextLength = 0 + self.h = h + self.x = 0 + + // Calculate for AAD at the begining + self.x = GF.calculateX(aad: aad, x: self.x, h: h, blockSize: blockSize) + } + + @discardableResult + func ghashUpdate(block ciphertextBlock: Array) -> UInt128 { + self.ciphertextLength += ciphertextBlock.count + self.x = GF.calculateX(block: addPadding(ciphertextBlock, blockSize: self.blockSize), x: self.x, h: self.h, blockSize: self.blockSize) + return self.x + } + + func ghashFinish() -> UInt128 { + // len(A) || len(C) + let len = UInt128(a: UInt64(aadLength * 8), b: UInt64(ciphertextLength * 8)) + x = GF.multiply(self.x ^ len, self.h) + return self.x + } + + // GHASH. One-time calculation + static func ghash(x startx: UInt128 = 0, h: UInt128, aad: Array, ciphertext: Array, blockSize: Int) -> UInt128 { + var x = self.calculateX(aad: aad, x: startx, h: h, blockSize: blockSize) + x = self.calculateX(ciphertext: ciphertext, x: x, h: h, blockSize: blockSize) + + // len(aad) || len(ciphertext) + let len = UInt128(a: UInt64(aad.count * 8), b: UInt64(ciphertext.count * 8)) + x = self.multiply(x ^ len, h) + + return x + } + + // Calculate Ciphertext part, for all blocks + // Not used with incremental calculation. + private static func calculateX(ciphertext: [UInt8], x startx: UInt128, h: UInt128, blockSize: Int) -> UInt128 { + let pciphertext = addPadding(ciphertext, blockSize: blockSize) + let blocksCount = pciphertext.count / blockSize + + var x = startx + for i in 0.., x: UInt128, h: UInt128, blockSize: Int) -> UInt128 { + let k = x ^ UInt128(ciphertextBlock) + return self.multiply(k, h) + } + + // Calculate AAD part, for all blocks + private static func calculateX(aad: [UInt8], x startx: UInt128, h: UInt128, blockSize: Int) -> UInt128 { + let paad = addPadding(aad, blockSize: blockSize) + let blocksCount = paad.count / blockSize + + var x = startx + for i in 0.. UInt128 { + var z: UInt128 = 0 + var v = x + var k = UInt128(a: 1 << 63, b: 0) + + for _ in 0..<128 { + if y & k == k { + z = z ^ v + } + + if v & 1 != 1 { + v = v >> 1 + } else { + v = (v >> 1) ^ self.r + } + + k = k >> 1 + } + + return z + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/OFB.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/OFB.swift new file mode 100644 index 0000000..494018b --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/OFB.swift @@ -0,0 +1,70 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// Output Feedback (OFB) +// + +public struct OFB: BlockMode { + public enum Error: Swift.Error { + /// Invalid IV + case invalidInitializationVector + } + + public let options: BlockModeOption = [.initializationVectorRequired, .useEncryptToDecrypt] + private let iv: Array + + public init(iv: Array) { + self.iv = iv + } + + public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { + if self.iv.count != blockSize { + throw Error.invalidInitializationVector + } + + return OFBModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation) + } +} + +struct OFBModeWorker: BlockModeWorker { + let cipherOperation: CipherOperationOnBlock + let blockSize: Int + let additionalBufferSize: Int = 0 + private let iv: ArraySlice + private var prev: ArraySlice? + + init(blockSize: Int, iv: ArraySlice, cipherOperation: @escaping CipherOperationOnBlock) { + self.blockSize = blockSize + self.iv = iv + self.cipherOperation = cipherOperation + } + + mutating func encrypt(block plaintext: ArraySlice) -> Array { + guard let ciphertext = cipherOperation(prev ?? iv) else { + return Array(plaintext) + } + self.prev = ciphertext.slice + return xor(plaintext, ciphertext) + } + + mutating func decrypt(block ciphertext: ArraySlice) -> Array { + guard let decrypted = cipherOperation(prev ?? iv) else { + return Array(ciphertext) + } + let plaintext: Array = xor(decrypted, ciphertext) + prev = decrypted.slice + return plaintext + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/PCBC.swift b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/PCBC.swift new file mode 100644 index 0000000..cb2c0b9 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/BlockMode/PCBC.swift @@ -0,0 +1,70 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// Propagating Cipher Block Chaining (PCBC) +// + +public struct PCBC: BlockMode { + public enum Error: Swift.Error { + /// Invalid IV + case invalidInitializationVector + } + + public let options: BlockModeOption = [.initializationVectorRequired, .paddingRequired] + private let iv: Array + + public init(iv: Array) { + self.iv = iv + } + + public func worker(blockSize: Int, cipherOperation: @escaping CipherOperationOnBlock) throws -> CipherModeWorker { + if self.iv.count != blockSize { + throw Error.invalidInitializationVector + } + + return PCBCModeWorker(blockSize: blockSize, iv: self.iv.slice, cipherOperation: cipherOperation) + } +} + +struct PCBCModeWorker: BlockModeWorker { + let cipherOperation: CipherOperationOnBlock + var blockSize: Int + let additionalBufferSize: Int = 0 + private let iv: ArraySlice + private var prev: ArraySlice? + + init(blockSize: Int, iv: ArraySlice, cipherOperation: @escaping CipherOperationOnBlock) { + self.blockSize = blockSize + self.iv = iv + self.cipherOperation = cipherOperation + } + + mutating func encrypt(block plaintext: ArraySlice) -> Array { + guard let ciphertext = cipherOperation(xor(prev ?? iv, plaintext)) else { + return Array(plaintext) + } + self.prev = xor(plaintext, ciphertext.slice) + return ciphertext + } + + mutating func decrypt(block ciphertext: ArraySlice) -> Array { + guard let plaintext = cipherOperation(ciphertext) else { + return Array(ciphertext) + } + let result: Array = xor(prev ?? self.iv, plaintext) + self.prev = xor(plaintext.slice, ciphertext) + return result + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Blowfish.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Blowfish.swift new file mode 100644 index 0000000..573ef3b --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Blowfish.swift @@ -0,0 +1,537 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// https://en.wikipedia.org/wiki/Blowfish_(cipher) +// Based on Paul Kocher implementation +// + +public final class Blowfish { + public enum Error: Swift.Error { + /// Data padding is required + case dataPaddingRequired + /// Invalid key or IV + case invalidKeyOrInitializationVector + /// Invalid IV + case invalidInitializationVector + /// Invalid block mode + case invalidBlockMode + } + + public static let blockSize: Int = 8 // 64 bit + public let keySize: Int + + private let blockMode: BlockMode + private let padding: Padding + private var decryptWorker: CipherModeWorker! + private var encryptWorker: CipherModeWorker! + + private let N = 16 // rounds + private var P: Array + private var S: Array> + private let origP: Array = [ + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, + 0x299f31d0, 0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, + 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, + 0xb5470917, 0x9216d5d9, 0x8979fb1b + ] + + private let origS: Array> = [ + [ + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a + ], + [ + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 + ], + [ + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 + ], + [ + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + ] + ] + + public init(key: Array, blockMode: BlockMode = CBC(iv: Array(repeating: 0, count: Blowfish.blockSize)), padding: Padding) throws { + precondition(key.count >= 5 && key.count <= 56) + + self.blockMode = blockMode + self.padding = padding + self.keySize = key.count + + self.S = self.origS + self.P = self.origP + + self.expandKey(key: key) + try self.setupBlockModeWorkers() + } + + private func setupBlockModeWorkers() throws { + self.encryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: self.encrypt) + + if self.blockMode.options.contains(.useEncryptToDecrypt) { + self.decryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: self.encrypt) + } else { + self.decryptWorker = try self.blockMode.worker(blockSize: Blowfish.blockSize, cipherOperation: self.decrypt) + } + } + + private func reset() { + self.S = self.origS + self.P = self.origP + // todo expand key + } + + private func expandKey(key: Array) { + var j = 0 + for i in 0..<(self.N + 2) { + var data: UInt32 = 0x0 + for _ in 0..<4 { + data = (data << 8) | UInt32(key[j]) + j += 1 + if j >= key.count { + j = 0 + } + } + self.P[i] ^= data + } + + var datal: UInt32 = 0 + var datar: UInt32 = 0 + + for i in stride(from: 0, to: self.N + 2, by: 2) { + self.encryptBlowfishBlock(l: &datal, r: &datar) + self.P[i] = datal + self.P[i + 1] = datar + } + + for i in 0..<4 { + for j in stride(from: 0, to: 256, by: 2) { + self.encryptBlowfishBlock(l: &datal, r: &datar) + self.S[i][j] = datal + self.S[i][j + 1] = datar + } + } + } + + fileprivate func encrypt(block: ArraySlice) -> Array? { + var result = Array() + + var l = UInt32(bytes: block[block.startIndex..> 24) & 0xff), + UInt8((l >> 16) & 0xff) + ] + result += [ + UInt8((l >> 8) & 0xff), + UInt8((l >> 0) & 0xff) + ] + result += [ + UInt8((r >> 24) & 0xff), + UInt8((r >> 16) & 0xff) + ] + result += [ + UInt8((r >> 8) & 0xff), + UInt8((r >> 0) & 0xff) + ] + + return result + } + + fileprivate func decrypt(block: ArraySlice) -> Array? { + var result = Array() + + var l = UInt32(bytes: block[block.startIndex..> 24) & 0xff), + UInt8((l >> 16) & 0xff) + ] + result += [ + UInt8((l >> 8) & 0xff), + UInt8((l >> 0) & 0xff) + ] + result += [ + UInt8((r >> 24) & 0xff), + UInt8((r >> 16) & 0xff) + ] + result += [ + UInt8((r >> 8) & 0xff), + UInt8((r >> 0) & 0xff) + ] + return result + } + + /// Encrypts the 8-byte padded buffer + /// + /// - Parameters: + /// - l: left half + /// - r: right half + private func encryptBlowfishBlock(l: inout UInt32, r: inout UInt32) { + var Xl = l + var Xr = r + + for i in 0.. UInt32 { + let f1 = self.S[0][Int(x >> 24) & 0xff] + let f2 = self.S[1][Int(x >> 16) & 0xff] + let f3 = self.S[2][Int(x >> 8) & 0xff] + let f4 = self.S[3][Int(x & 0xff)] + return ((f1 &+ f2) ^ f3) &+ f4 + } +} + +extension Blowfish: Cipher { + /// Encrypt the 8-byte padded buffer, block by block. Note that for amounts of data larger than a block, it is not safe to just call encrypt() on successive blocks. + /// + /// - Parameter bytes: Plaintext data + /// - Returns: Encrypted data + public func encrypt(_ bytes: C) throws -> Array where C.Element == UInt8, C.Index == Int { + let bytes = self.padding.add(to: Array(bytes), blockSize: Blowfish.blockSize) // FIXME: Array(bytes) copies + + var out = Array() + out.reserveCapacity(bytes.count) + + for chunk in bytes.batched(by: Blowfish.blockSize) { + out += self.encryptWorker.encrypt(block: chunk) + } + + if self.blockMode.options.contains(.paddingRequired) && (out.count % Blowfish.blockSize != 0) { + throw Error.dataPaddingRequired + } + + return out + } + + /// Decrypt the 8-byte padded buffer + /// + /// - Parameter bytes: Ciphertext data + /// - Returns: Plaintext data + public func decrypt(_ bytes: C) throws -> Array where C.Element == UInt8, C.Index == Int { + if self.blockMode.options.contains(.paddingRequired) && (bytes.count % Blowfish.blockSize != 0) { + throw Error.dataPaddingRequired + } + + var out = Array() + out.reserveCapacity(bytes.count) + + for chunk in Array(bytes).batched(by: Blowfish.blockSize) { + out += self.decryptWorker.decrypt(block: chunk) // FIXME: copying here is innefective + } + + out = self.padding.remove(from: out, blockSize: Blowfish.blockSize) + + return out + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/CBCMAC.swift b/Pods/CryptoSwift/Sources/CryptoSwift/CBCMAC.swift new file mode 100644 index 0000000..0cd6029 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/CBCMAC.swift @@ -0,0 +1,30 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public final class CBCMAC: CMAC { + public override func authenticate(_ bytes: Array) throws -> Array { + var inBytes = bytes + bitPadding(to: &inBytes, blockSize: CMAC.BlockSize) + let blocks = inBytes.batched(by: CMAC.BlockSize) + + var lastBlockEncryptionResult: [UInt8] = CBCMAC.Zero + try blocks.forEach { block in + let aes = try AES(key: Array(key), blockMode: CBC(iv: lastBlockEncryptionResult), padding: .noPadding) + lastBlockEncryptionResult = try aes.encrypt(block) + } + + return lastBlockEncryptionResult + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/CMAC.swift b/Pods/CryptoSwift/Sources/CryptoSwift/CMAC.swift new file mode 100644 index 0000000..a4e54bc --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/CMAC.swift @@ -0,0 +1,104 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public class CMAC: Authenticator { + public enum Error: Swift.Error { + case wrongKeyLength + } + + internal let key: SecureBytes + + internal static let BlockSize: Int = 16 + internal static let Zero: Array = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] + private static let Rb: Array = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87] + + public init(key: Array) throws { + if key.count != 16 { + throw Error.wrongKeyLength + } + self.key = SecureBytes(bytes: key) + } + + // MARK: Authenticator + + public func authenticate(_ bytes: Array) throws -> Array { + let aes = try AES(key: Array(key), blockMode: CBC(iv: CMAC.Zero), padding: .noPadding) + + let l = try aes.encrypt(CMAC.Zero) + var subKey1 = self.leftShiftOneBit(l) + if (l[0] & 0x80) != 0 { + subKey1 = xor(CMAC.Rb, subKey1) + } + var subKey2 = self.leftShiftOneBit(subKey1) + if (subKey1[0] & 0x80) != 0 { + subKey2 = xor(CMAC.Rb, subKey2) + } + + let lastBlockComplete: Bool + let blockCount = (bytes.count + CMAC.BlockSize - 1) / CMAC.BlockSize + if blockCount == 0 { + lastBlockComplete = false + } else { + lastBlockComplete = bytes.count % CMAC.BlockSize == 0 + } + var paddedBytes = bytes + if !lastBlockComplete { + bitPadding(to: &paddedBytes, blockSize: CMAC.BlockSize) + } + + var blocks = Array(paddedBytes.batched(by: CMAC.BlockSize)) + var lastBlock = blocks.popLast()! + if lastBlockComplete { + lastBlock = xor(lastBlock, subKey1) + } else { + lastBlock = xor(lastBlock, subKey2) + } + + var x = Array(repeating: 0x00, count: CMAC.BlockSize) + var y = Array(repeating: 0x00, count: CMAC.BlockSize) + for block in blocks { + y = xor(block, x) + x = try aes.encrypt(y) + } + // the difference between CMAC and CBC-MAC is that CMAC xors the final block with a secret value + y = self.process(lastBlock: lastBlock, with: x) + return try aes.encrypt(y) + } + + func process(lastBlock: ArraySlice, with x: [UInt8]) -> [UInt8] { + xor(lastBlock, x) + } + + // MARK: Helper methods + + /** + Performs left shift by one bit to the bit string aquired after concatenating al bytes in the byte array + - parameters: + - bytes: byte array + - returns: bit shifted bit string split again in array of bytes + */ + private func leftShiftOneBit(_ bytes: Array) -> Array { + var shifted = Array(repeating: 0x00, count: bytes.count) + let last = bytes.count - 1 + for index in 0.. +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// https://tools.ietf.org/html/rfc7539 +// + +public final class ChaCha20: BlockCipher { + public enum Error: Swift.Error { + case invalidKeyOrInitializationVector + case notSupported + } + + public static let blockSize = 64 // 512 / 8 + public let keySize: Int + + fileprivate let key: Key + fileprivate var counter: Array + + public init(key: Array, iv nonce: Array) throws { + precondition(nonce.count == 12 || nonce.count == 8) + + if key.count != 32 { + throw Error.invalidKeyOrInitializationVector + } + + self.key = Key(bytes: key) + self.keySize = self.key.count + + if nonce.count == 8 { + self.counter = [0, 0, 0, 0, 0, 0, 0, 0] + nonce + } else { + self.counter = [0, 0, 0, 0] + nonce + } + + assert(self.counter.count == 16) + } + + /// https://tools.ietf.org/html/rfc7539#section-2.3. + fileprivate func core(block: inout Array, counter: Array, key: Array) { + precondition(block.count == ChaCha20.blockSize) + precondition(counter.count == 16) + precondition(key.count == 32) + + let j0: UInt32 = 0x61707865 + let j1: UInt32 = 0x3320646e // 0x3620646e sigma/tau + let j2: UInt32 = 0x79622d32 + let j3: UInt32 = 0x6b206574 + let j4: UInt32 = UInt32(bytes: key[0..<4]).bigEndian + let j5: UInt32 = UInt32(bytes: key[4..<8]).bigEndian + let j6: UInt32 = UInt32(bytes: key[8..<12]).bigEndian + let j7: UInt32 = UInt32(bytes: key[12..<16]).bigEndian + let j8: UInt32 = UInt32(bytes: key[16..<20]).bigEndian + let j9: UInt32 = UInt32(bytes: key[20..<24]).bigEndian + let j10: UInt32 = UInt32(bytes: key[24..<28]).bigEndian + let j11: UInt32 = UInt32(bytes: key[28..<32]).bigEndian + let j12: UInt32 = UInt32(bytes: counter[0..<4]).bigEndian + let j13: UInt32 = UInt32(bytes: counter[4..<8]).bigEndian + let j14: UInt32 = UInt32(bytes: counter[8..<12]).bigEndian + let j15: UInt32 = UInt32(bytes: counter[12..<16]).bigEndian + + var (x0, x1, x2, x3, x4, x5, x6, x7) = (j0, j1, j2, j3, j4, j5, j6, j7) + var (x8, x9, x10, x11, x12, x13, x14, x15) = (j8, j9, j10, j11, j12, j13, j14, j15) + + for _ in 0..<10 { // 20 rounds + x0 = x0 &+ x4 + x12 ^= x0 + x12 = (x12 << 16) | (x12 >> 16) + x8 = x8 &+ x12 + x4 ^= x8 + x4 = (x4 << 12) | (x4 >> 20) + x0 = x0 &+ x4 + x12 ^= x0 + x12 = (x12 << 8) | (x12 >> 24) + x8 = x8 &+ x12 + x4 ^= x8 + x4 = (x4 << 7) | (x4 >> 25) + x1 = x1 &+ x5 + x13 ^= x1 + x13 = (x13 << 16) | (x13 >> 16) + x9 = x9 &+ x13 + x5 ^= x9 + x5 = (x5 << 12) | (x5 >> 20) + x1 = x1 &+ x5 + x13 ^= x1 + x13 = (x13 << 8) | (x13 >> 24) + x9 = x9 &+ x13 + x5 ^= x9 + x5 = (x5 << 7) | (x5 >> 25) + x2 = x2 &+ x6 + x14 ^= x2 + x14 = (x14 << 16) | (x14 >> 16) + x10 = x10 &+ x14 + x6 ^= x10 + x6 = (x6 << 12) | (x6 >> 20) + x2 = x2 &+ x6 + x14 ^= x2 + x14 = (x14 << 8) | (x14 >> 24) + x10 = x10 &+ x14 + x6 ^= x10 + x6 = (x6 << 7) | (x6 >> 25) + x3 = x3 &+ x7 + x15 ^= x3 + x15 = (x15 << 16) | (x15 >> 16) + x11 = x11 &+ x15 + x7 ^= x11 + x7 = (x7 << 12) | (x7 >> 20) + x3 = x3 &+ x7 + x15 ^= x3 + x15 = (x15 << 8) | (x15 >> 24) + x11 = x11 &+ x15 + x7 ^= x11 + x7 = (x7 << 7) | (x7 >> 25) + x0 = x0 &+ x5 + x15 ^= x0 + x15 = (x15 << 16) | (x15 >> 16) + x10 = x10 &+ x15 + x5 ^= x10 + x5 = (x5 << 12) | (x5 >> 20) + x0 = x0 &+ x5 + x15 ^= x0 + x15 = (x15 << 8) | (x15 >> 24) + x10 = x10 &+ x15 + x5 ^= x10 + x5 = (x5 << 7) | (x5 >> 25) + x1 = x1 &+ x6 + x12 ^= x1 + x12 = (x12 << 16) | (x12 >> 16) + x11 = x11 &+ x12 + x6 ^= x11 + x6 = (x6 << 12) | (x6 >> 20) + x1 = x1 &+ x6 + x12 ^= x1 + x12 = (x12 << 8) | (x12 >> 24) + x11 = x11 &+ x12 + x6 ^= x11 + x6 = (x6 << 7) | (x6 >> 25) + x2 = x2 &+ x7 + x13 ^= x2 + x13 = (x13 << 16) | (x13 >> 16) + x8 = x8 &+ x13 + x7 ^= x8 + x7 = (x7 << 12) | (x7 >> 20) + x2 = x2 &+ x7 + x13 ^= x2 + x13 = (x13 << 8) | (x13 >> 24) + x8 = x8 &+ x13 + x7 ^= x8 + x7 = (x7 << 7) | (x7 >> 25) + x3 = x3 &+ x4 + x14 ^= x3 + x14 = (x14 << 16) | (x14 >> 16) + x9 = x9 &+ x14 + x4 ^= x9 + x4 = (x4 << 12) | (x4 >> 20) + x3 = x3 &+ x4 + x14 ^= x3 + x14 = (x14 << 8) | (x14 >> 24) + x9 = x9 &+ x14 + x4 ^= x9 + x4 = (x4 << 7) | (x4 >> 25) + } + + x0 = x0 &+ j0 + x1 = x1 &+ j1 + x2 = x2 &+ j2 + x3 = x3 &+ j3 + x4 = x4 &+ j4 + x5 = x5 &+ j5 + x6 = x6 &+ j6 + x7 = x7 &+ j7 + x8 = x8 &+ j8 + x9 = x9 &+ j9 + x10 = x10 &+ j10 + x11 = x11 &+ j11 + x12 = x12 &+ j12 + x13 = x13 &+ j13 + x14 = x14 &+ j14 + x15 = x15 &+ j15 + + block.replaceSubrange(0..<4, with: x0.bigEndian.bytes()) + block.replaceSubrange(4..<8, with: x1.bigEndian.bytes()) + block.replaceSubrange(8..<12, with: x2.bigEndian.bytes()) + block.replaceSubrange(12..<16, with: x3.bigEndian.bytes()) + block.replaceSubrange(16..<20, with: x4.bigEndian.bytes()) + block.replaceSubrange(20..<24, with: x5.bigEndian.bytes()) + block.replaceSubrange(24..<28, with: x6.bigEndian.bytes()) + block.replaceSubrange(28..<32, with: x7.bigEndian.bytes()) + block.replaceSubrange(32..<36, with: x8.bigEndian.bytes()) + block.replaceSubrange(36..<40, with: x9.bigEndian.bytes()) + block.replaceSubrange(40..<44, with: x10.bigEndian.bytes()) + block.replaceSubrange(44..<48, with: x11.bigEndian.bytes()) + block.replaceSubrange(48..<52, with: x12.bigEndian.bytes()) + block.replaceSubrange(52..<56, with: x13.bigEndian.bytes()) + block.replaceSubrange(56..<60, with: x14.bigEndian.bytes()) + block.replaceSubrange(60..<64, with: x15.bigEndian.bytes()) + } + + // XORKeyStream + func process(bytes: ArraySlice, counter: inout Array, key: Array) -> Array { + precondition(counter.count == 16) + precondition(key.count == 32) + + var block = Array(repeating: 0, count: ChaCha20.blockSize) + var bytesSlice = bytes + var out = Array(reserveCapacity: bytesSlice.count) + + while bytesSlice.count >= ChaCha20.blockSize { + self.core(block: &block, counter: counter, key: key) + for (i, x) in block.enumerated() { + out.append(bytesSlice[bytesSlice.startIndex + i] ^ x) + } + var u: UInt32 = 1 + for i in 0..<4 { + u += UInt32(counter[i]) + counter[i] = UInt8(u & 0xff) + u >>= 8 + } + bytesSlice = bytesSlice[bytesSlice.startIndex + ChaCha20.blockSize..) throws -> Array { + self.process(bytes: bytes, counter: &self.counter, key: Array(self.key)) + } + + public func decrypt(_ bytes: ArraySlice) throws -> Array { + try self.encrypt(bytes) + } +} + +// MARK: Encryptor + +extension ChaCha20 { + public struct ChaChaEncryptor: Cryptor, Updatable { + private var accumulated = Array() + private let chacha: ChaCha20 + + init(chacha: ChaCha20) { + self.chacha = chacha + } + + public mutating func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array { + self.accumulated += bytes + + var encrypted = Array() + encrypted.reserveCapacity(self.accumulated.count) + for chunk in self.accumulated.batched(by: ChaCha20.blockSize) { + if isLast || self.accumulated.count >= ChaCha20.blockSize { + encrypted += try self.chacha.encrypt(chunk) + self.accumulated.removeFirst(chunk.count) // TODO: improve performance + } + } + return encrypted + } + + public func seek(to: Int) throws { + throw Error.notSupported + } + } +} + +// MARK: Decryptor + +extension ChaCha20 { + public struct ChaChaDecryptor: Cryptor, Updatable { + private var accumulated = Array() + + private var offset: Int = 0 + private var offsetToRemove: Int = 0 + private let chacha: ChaCha20 + + init(chacha: ChaCha20) { + self.chacha = chacha + } + + public mutating func update(withBytes bytes: ArraySlice, isLast: Bool = true) throws -> Array { + // prepend "offset" number of bytes at the beginning + if self.offset > 0 { + self.accumulated += Array(repeating: 0, count: self.offset) + bytes + self.offsetToRemove = self.offset + self.offset = 0 + } else { + self.accumulated += bytes + } + + var plaintext = Array() + plaintext.reserveCapacity(self.accumulated.count) + for chunk in self.accumulated.batched(by: ChaCha20.blockSize) { + if isLast || self.accumulated.count >= ChaCha20.blockSize { + plaintext += try self.chacha.decrypt(chunk) + + // remove "offset" from the beginning of first chunk + if self.offsetToRemove > 0 { + plaintext.removeFirst(self.offsetToRemove) // TODO: improve performance + self.offsetToRemove = 0 + } + + self.accumulated.removeFirst(chunk.count) + } + } + + return plaintext + } + + public func seek(to: Int) throws { + throw Error.notSupported + } + } +} + +// MARK: Cryptors + +extension ChaCha20: Cryptors { + //TODO: Use BlockEncryptor/BlockDecryptor + + public func makeEncryptor() -> Cryptor & Updatable { + ChaCha20.ChaChaEncryptor(chacha: self) + } + + public func makeDecryptor() -> Cryptor & Updatable { + ChaCha20.ChaChaDecryptor(chacha: self) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Checksum.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Checksum.swift new file mode 100644 index 0000000..d3bac93 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Checksum.swift @@ -0,0 +1,193 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +/// CRC - cyclic redundancy check code. +public final class Checksum { + private static let table32: Array = [ + 0x0000_0000, 0x7707_3096, 0xEE0E_612C, 0x9909_51BA, 0x076D_C419, 0x706A_F48F, 0xE963_A535, 0x9E64_95A3, + 0x0EDB_8832, 0x79DC_B8A4, 0xE0D5_E91E, 0x97D2_D988, 0x09B6_4C2B, 0x7EB1_7CBD, 0xE7B8_2D07, 0x90BF_1D91, + 0x1DB7_1064, 0x6AB0_20F2, 0xF3B9_7148, 0x84BE_41DE, 0x1ADA_D47D, 0x6DDD_E4EB, 0xF4D4_B551, 0x83D3_85C7, + 0x136C_9856, 0x646B_A8C0, 0xFD62_F97A, 0x8A65_C9EC, 0x1401_5C4F, 0x6306_6CD9, 0xFA0F_3D63, 0x8D08_0DF5, + 0x3B6E_20C8, 0x4C69_105E, 0xD560_41E4, 0xA267_7172, 0x3C03_E4D1, 0x4B04_D447, 0xD20D_85FD, 0xA50A_B56B, + 0x35B5_A8FA, 0x42B2_986C, 0xDBBB_C9D6, 0xACBC_F940, 0x32D8_6CE3, 0x45DF_5C75, 0xDCD6_0DCF, 0xABD1_3D59, + 0x26D9_30AC, 0x51DE_003A, 0xC8D7_5180, 0xBFD0_6116, 0x21B4_F4B5, 0x56B3_C423, 0xCFBA_9599, 0xB8BD_A50F, + 0x2802_B89E, 0x5F05_8808, 0xC60C_D9B2, 0xB10B_E924, 0x2F6F_7C87, 0x5868_4C11, 0xC161_1DAB, 0xB666_2D3D, + 0x76DC_4190, 0x01DB_7106, 0x98D2_20BC, 0xEFD5_102A, 0x71B1_8589, 0x06B6_B51F, 0x9FBF_E4A5, 0xE8B8_D433, + 0x7807_C9A2, 0x0F00_F934, 0x9609_A88E, 0xE10E_9818, 0x7F6A_0DBB, 0x086D_3D2D, 0x9164_6C97, 0xE663_5C01, + 0x6B6B_51F4, 0x1C6C_6162, 0x8565_30D8, 0xF262_004E, 0x6C06_95ED, 0x1B01_A57B, 0x8208_F4C1, 0xF50F_C457, + 0x65B0_D9C6, 0x12B7_E950, 0x8BBE_B8EA, 0xFCB9_887C, 0x62DD_1DDF, 0x15DA_2D49, 0x8CD3_7CF3, 0xFBD4_4C65, + 0x4DB2_6158, 0x3AB5_51CE, 0xA3BC_0074, 0xD4BB_30E2, 0x4ADF_A541, 0x3DD8_95D7, 0xA4D1_C46D, 0xD3D6_F4FB, + 0x4369_E96A, 0x346E_D9FC, 0xAD67_8846, 0xDA60_B8D0, 0x4404_2D73, 0x3303_1DE5, 0xAA0A_4C5F, 0xDD0D_7CC9, + 0x5005_713C, 0x2702_41AA, 0xBE0B_1010, 0xC90C_2086, 0x5768_B525, 0x206F_85B3, 0xB966_D409, 0xCE61_E49F, + 0x5EDE_F90E, 0x29D9_C998, 0xB0D0_9822, 0xC7D7_A8B4, 0x59B3_3D17, 0x2EB4_0D81, 0xB7BD_5C3B, 0xC0BA_6CAD, + 0xEDB8_8320, 0x9ABF_B3B6, 0x03B6_E20C, 0x74B1_D29A, 0xEAD5_4739, 0x9DD2_77AF, 0x04DB_2615, 0x73DC_1683, + 0xE363_0B12, 0x9464_3B84, 0x0D6D_6A3E, 0x7A6A_5AA8, 0xE40E_CF0B, 0x9309_FF9D, 0x0A00_AE27, 0x7D07_9EB1, + 0xF00F_9344, 0x8708_A3D2, 0x1E01_F268, 0x6906_C2FE, 0xF762_575D, 0x8065_67CB, 0x196C_3671, 0x6E6B_06E7, + 0xFED4_1B76, 0x89D3_2BE0, 0x10DA_7A5A, 0x67DD_4ACC, 0xF9B9_DF6F, 0x8EBE_EFF9, 0x17B7_BE43, 0x60B0_8ED5, + 0xD6D6_A3E8, 0xA1D1_937E, 0x38D8_C2C4, 0x4FDF_F252, 0xD1BB_67F1, 0xA6BC_5767, 0x3FB5_06DD, 0x48B2_364B, + 0xD80D_2BDA, 0xAF0A_1B4C, 0x3603_4AF6, 0x4104_7A60, 0xDF60_EFC3, 0xA867_DF55, 0x316E_8EEF, 0x4669_BE79, + 0xCB61_B38C, 0xBC66_831A, 0x256F_D2A0, 0x5268_E236, 0xCC0C_7795, 0xBB0B_4703, 0x2202_16B9, 0x5505_262F, + 0xC5BA_3BBE, 0xB2BD_0B28, 0x2BB4_5A92, 0x5CB3_6A04, 0xC2D7_FFA7, 0xB5D0_CF31, 0x2CD9_9E8B, 0x5BDE_AE1D, + 0x9B64_C2B0, 0xEC63_F226, 0x756A_A39C, 0x026D_930A, 0x9C09_06A9, 0xEB0E_363F, 0x7207_6785, 0x0500_5713, + 0x95BF_4A82, 0xE2B8_7A14, 0x7BB1_2BAE, 0x0CB6_1B38, 0x92D2_8E9B, 0xE5D5_BE0D, 0x7CDC_EFB7, 0x0BDB_DF21, + 0x86D3_D2D4, 0xF1D4_E242, 0x68DD_B3F8, 0x1FDA_836E, 0x81BE_16CD, 0xF6B9_265B, 0x6FB0_77E1, 0x18B7_4777, + 0x8808_5AE6, 0xFF0F_6A70, 0x6606_3BCA, 0x1101_0B5C, 0x8F65_9EFF, 0xF862_AE69, 0x616B_FFD3, 0x166C_CF45, + 0xA00A_E278, 0xD70D_D2EE, 0x4E04_8354, 0x3903_B3C2, 0xA767_2661, 0xD060_16F7, 0x4969_474D, 0x3E6E_77DB, + 0xAED1_6A4A, 0xD9D6_5ADC, 0x40DF_0B66, 0x37D8_3BF0, 0xA9BC_AE53, 0xDEBB_9EC5, 0x47B2_CF7F, 0x30B5_FFE9, + 0xBDBD_F21C, 0xCABA_C28A, 0x53B3_9330, 0x24B4_A3A6, 0xBAD0_3605, 0xCDD7_0693, 0x54DE_5729, 0x23D9_67BF, + 0xB366_7A2E, 0xC461_4AB8, 0x5D68_1B02, 0x2A6F_2B94, 0xB40B_BE37, 0xC30C_8EA1, 0x5A05_DF1B, 0x2D02_EF8D + ] + + private static let table32c: Array = [ + 0x0000_0000, 0xF26B_8303, 0xE13B_70F7, 0x1350_F3F4, 0xC79A_971F, 0x35F1_141C, 0x26A1_E7E8, 0xD4CA_64EB, + 0x8AD9_58CF, 0x78B2_DBCC, 0x6BE2_2838, 0x9989_AB3B, 0x4D43_CFD0, 0xBF28_4CD3, 0xAC78_BF27, 0x5E13_3C24, + 0x105E_C76F, 0xE235_446C, 0xF165_B798, 0x030E_349B, 0xD7C4_5070, 0x25AF_D373, 0x36FF_2087, 0xC494_A384, + 0x9A87_9FA0, 0x68EC_1CA3, 0x7BBC_EF57, 0x89D7_6C54, 0x5D1D_08BF, 0xAF76_8BBC, 0xBC26_7848, 0x4E4D_FB4B, + 0x20BD_8EDE, 0xD2D6_0DDD, 0xC186_FE29, 0x33ED_7D2A, 0xE727_19C1, 0x154C_9AC2, 0x061C_6936, 0xF477_EA35, + 0xAA64_D611, 0x580F_5512, 0x4B5F_A6E6, 0xB934_25E5, 0x6DFE_410E, 0x9F95_C20D, 0x8CC5_31F9, 0x7EAE_B2FA, + 0x30E3_49B1, 0xC288_CAB2, 0xD1D8_3946, 0x23B3_BA45, 0xF779_DEAE, 0x0512_5DAD, 0x1642_AE59, 0xE429_2D5A, + 0xBA3A_117E, 0x4851_927D, 0x5B01_6189, 0xA96A_E28A, 0x7DA0_8661, 0x8FCB_0562, 0x9C9B_F696, 0x6EF0_7595, + 0x417B_1DBC, 0xB310_9EBF, 0xA040_6D4B, 0x522B_EE48, 0x86E1_8AA3, 0x748A_09A0, 0x67DA_FA54, 0x95B1_7957, + 0xCBA2_4573, 0x39C9_C670, 0x2A99_3584, 0xD8F2_B687, 0x0C38_D26C, 0xFE53_516F, 0xED03_A29B, 0x1F68_2198, + 0x5125_DAD3, 0xA34E_59D0, 0xB01E_AA24, 0x4275_2927, 0x96BF_4DCC, 0x64D4_CECF, 0x7784_3D3B, 0x85EF_BE38, + 0xDBFC_821C, 0x2997_011F, 0x3AC7_F2EB, 0xC8AC_71E8, 0x1C66_1503, 0xEE0D_9600, 0xFD5D_65F4, 0x0F36_E6F7, + 0x61C6_9362, 0x93AD_1061, 0x80FD_E395, 0x7296_6096, 0xA65C_047D, 0x5437_877E, 0x4767_748A, 0xB50C_F789, + 0xEB1F_CBAD, 0x1974_48AE, 0x0A24_BB5A, 0xF84F_3859, 0x2C85_5CB2, 0xDEEE_DFB1, 0xCDBE_2C45, 0x3FD5_AF46, + 0x7198_540D, 0x83F3_D70E, 0x90A3_24FA, 0x62C8_A7F9, 0xB602_C312, 0x4469_4011, 0x5739_B3E5, 0xA552_30E6, + 0xFB41_0CC2, 0x092A_8FC1, 0x1A7A_7C35, 0xE811_FF36, 0x3CDB_9BDD, 0xCEB0_18DE, 0xDDE0_EB2A, 0x2F8B_6829, + 0x82F6_3B78, 0x709D_B87B, 0x63CD_4B8F, 0x91A6_C88C, 0x456C_AC67, 0xB707_2F64, 0xA457_DC90, 0x563C_5F93, + 0x082F_63B7, 0xFA44_E0B4, 0xE914_1340, 0x1B7F_9043, 0xCFB5_F4A8, 0x3DDE_77AB, 0x2E8E_845F, 0xDCE5_075C, + 0x92A8_FC17, 0x60C3_7F14, 0x7393_8CE0, 0x81F8_0FE3, 0x5532_6B08, 0xA759_E80B, 0xB409_1BFF, 0x4662_98FC, + 0x1871_A4D8, 0xEA1A_27DB, 0xF94A_D42F, 0x0B21_572C, 0xDFEB_33C7, 0x2D80_B0C4, 0x3ED0_4330, 0xCCBB_C033, + 0xA24B_B5A6, 0x5020_36A5, 0x4370_C551, 0xB11B_4652, 0x65D1_22B9, 0x97BA_A1BA, 0x84EA_524E, 0x7681_D14D, + 0x2892_ED69, 0xDAF9_6E6A, 0xC9A9_9D9E, 0x3BC2_1E9D, 0xEF08_7A76, 0x1D63_F975, 0x0E33_0A81, 0xFC58_8982, + 0xB215_72C9, 0x407E_F1CA, 0x532E_023E, 0xA145_813D, 0x758F_E5D6, 0x87E4_66D5, 0x94B4_9521, 0x66DF_1622, + 0x38CC_2A06, 0xCAA7_A905, 0xD9F7_5AF1, 0x2B9C_D9F2, 0xFF56_BD19, 0x0D3D_3E1A, 0x1E6D_CDEE, 0xEC06_4EED, + 0xC38D_26C4, 0x31E6_A5C7, 0x22B6_5633, 0xD0DD_D530, 0x0417_B1DB, 0xF67C_32D8, 0xE52C_C12C, 0x1747_422F, + 0x4954_7E0B, 0xBB3F_FD08, 0xA86F_0EFC, 0x5A04_8DFF, 0x8ECE_E914, 0x7CA5_6A17, 0x6FF5_99E3, 0x9D9E_1AE0, + 0xD3D3_E1AB, 0x21B8_62A8, 0x32E8_915C, 0xC083_125F, 0x1449_76B4, 0xE622_F5B7, 0xF572_0643, 0x0719_8540, + 0x590A_B964, 0xAB61_3A67, 0xB831_C993, 0x4A5A_4A90, 0x9E90_2E7B, 0x6CFB_AD78, 0x7FAB_5E8C, 0x8DC0_DD8F, + 0xE330_A81A, 0x115B_2B19, 0x020B_D8ED, 0xF060_5BEE, 0x24AA_3F05, 0xD6C1_BC06, 0xC591_4FF2, 0x37FA_CCF1, + 0x69E9_F0D5, 0x9B82_73D6, 0x88D2_8022, 0x7AB9_0321, 0xAE73_67CA, 0x5C18_E4C9, 0x4F48_173D, 0xBD23_943E, + 0xF36E_6F75, 0x0105_EC76, 0x1255_1F82, 0xE03E_9C81, 0x34F4_F86A, 0xC69F_7B69, 0xD5CF_889D, 0x27A4_0B9E, + 0x79B7_37BA, 0x8BDC_B4B9, 0x988C_474D, 0x6AE7_C44E, 0xBE2D_A0A5, 0x4C46_23A6, 0x5F16_D052, 0xAD7D_5351 + ] + + private static let table16: Array = [ + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 + ] + + /// Polynomial: 0xEDB88320 (Reversed) - IEEE + func crc32(_ message: Array, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { + var crc: UInt32 = seed != nil ? seed! : 0xFFFF_FFFF + for chunk in message.batched(by: 256) { + for b in chunk { + let idx = Int((crc ^ UInt32(reflect ? b : reversed(b))) & 0xFF) + crc = (crc >> 8) ^ Checksum.table32[idx] + } + } + return (reflect ? crc : reversed(crc)) ^ 0xFFFF_FFFF + } + + /// Polynomial: 0x82F63B78 (Reversed) - Castagnoli + func crc32c(_ message: Array, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { + var crc: UInt32 = seed != nil ? seed! : 0xFFFF_FFFF + for chunk in message.batched(by: 256) { + for b in chunk { + let idx = Int((crc ^ UInt32(reflect ? b : reversed(b))) & 0xFF) + crc = (crc >> 8) ^ Checksum.table32c[idx] + } + } + return (reflect ? crc : reversed(crc)) ^ 0xFFFF_FFFF + } + + /// Polynomial: 0xA001 (Reversed) - IBM + func crc16(_ message: Array, seed: UInt16? = nil) -> UInt16 { + var crc: UInt16 = seed != nil ? seed! : 0x0000 + for chunk in message.batched(by: 256) { + for b in chunk { + crc = (crc >> 8) ^ Checksum.table16[Int((crc ^ UInt16(b)) & 0xFF)] + } + } + return crc + } +} + +// MARK: Public interface + +public extension Checksum { + /// Calculate CRC32. + /// + /// - parameter message: Message + /// - parameter seed: Seed value (Optional) + /// - parameter reflect: is reflect (default true) + /// + /// - returns: Calculated code + static func crc32(_ message: Array, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { + Checksum().crc32(message, seed: seed, reflect: reflect) + } + + /// Calculate CRC32C + /// + /// - parameter message: Message + /// - parameter seed: Seed value (Optional) + /// - parameter reflect: is reflect (default true) + /// + /// - returns: Calculated code + static func crc32c(_ message: Array, seed: UInt32? = nil, reflect: Bool = true) -> UInt32 { + Checksum().crc32c(message, seed: seed, reflect: reflect) + } + + /// Calculate CRC16 + /// + /// - parameter message: Message + /// - parameter seed: Seed value (Optional) + /// + /// - returns: Calculated code + static func crc16(_ message: Array, seed: UInt16? = nil) -> UInt16 { + Checksum().crc16(message, seed: seed) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Cipher.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Cipher.swift new file mode 100644 index 0000000..a5a09d9 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Cipher.swift @@ -0,0 +1,47 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public enum CipherError: Error { + case encrypt + case decrypt +} + +public protocol Cipher: class { + var keySize: Int { get } + + /// Encrypt given bytes at once + /// + /// - parameter bytes: Plaintext data + /// - returns: Encrypted data + func encrypt(_ bytes: ArraySlice) throws -> Array + func encrypt(_ bytes: Array) throws -> Array + + /// Decrypt given bytes at once + /// + /// - parameter bytes: Ciphertext data + /// - returns: Plaintext data + func decrypt(_ bytes: ArraySlice) throws -> Array + func decrypt(_ bytes: Array) throws -> Array +} + +extension Cipher { + public func encrypt(_ bytes: Array) throws -> Array { + try self.encrypt(bytes.slice) + } + + public func decrypt(_ bytes: Array) throws -> Array { + try self.decrypt(bytes.slice) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Collection+Extension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Collection+Extension.swift new file mode 100644 index 0000000..28a4d54 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Collection+Extension.swift @@ -0,0 +1,45 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// +extension Collection where Self.Element == UInt8, Self.Index == Int { + // Big endian order + func toUInt32Array() -> Array { + if isEmpty { + return [] + } + + var result = Array(reserveCapacity: 16) + for idx in stride(from: startIndex, to: endIndex, by: 4) { + let val = UInt32(bytes: self, fromIndex: idx).bigEndian + result.append(val) + } + + return result + } + + // Big endian order + func toUInt64Array() -> Array { + if isEmpty { + return [] + } + + var result = Array(reserveCapacity: 32) + for idx in stride(from: startIndex, to: endIndex, by: 8) { + let val = UInt64(bytes: self, fromIndex: idx).bigEndian + result.append(val) + } + + return result + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/CompactMap.swift b/Pods/CryptoSwift/Sources/CryptoSwift/CompactMap.swift new file mode 100644 index 0000000..c96123b --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/CompactMap.swift @@ -0,0 +1,23 @@ +//// CryptoSwift +// +// Copyright (C) 2014-2018 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +#if swift(>=4.1) +// TODO: remove this file when Xcode 9.2 is no longer used +#else + extension Sequence { + public func compactMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] { + try flatMap(transform) + } + } +#endif diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Cryptor.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Cryptor.swift new file mode 100644 index 0000000..34cd275 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Cryptor.swift @@ -0,0 +1,22 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +/// Cryptor (Encryptor or Decryptor) +public protocol Cryptor { + /// Seek to position in file, if block mode allows random access. + /// + /// - parameter to: new value of counter + mutating func seek(to: Int) throws +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Cryptors.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Cryptors.swift new file mode 100644 index 0000000..d0e5fd9 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Cryptors.swift @@ -0,0 +1,42 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +#if canImport(Darwin) + import Darwin +#else + import Glibc +#endif + +/// Worker cryptor/decryptor of `Updatable` types +public protocol Cryptors: class { + + /// Cryptor suitable for encryption + func makeEncryptor() throws -> Cryptor & Updatable + + /// Cryptor suitable for decryption + func makeDecryptor() throws -> Cryptor & Updatable + + /// Generate array of random bytes. Helper function. + static func randomIV(_ blockSize: Int) -> Array +} + +extension Cryptors { + /// Generate array of random values. + /// Convenience helper that uses `Swift.RandomNumberGenerator`. + /// - Parameter count: Length of array + public static func randomIV(_ count: Int) -> Array { + (0.. +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +@available(*, renamed: "Digest") +public typealias Hash = Digest + +/// Hash functions to calculate Digest. +public struct Digest { + /// Calculate MD5 Digest + /// - parameter bytes: input message + /// - returns: Digest bytes + public static func md5(_ bytes: Array) -> Array { + MD5().calculate(for: bytes) + } + + /// Calculate SHA1 Digest + /// - parameter bytes: input message + /// - returns: Digest bytes + public static func sha1(_ bytes: Array) -> Array { + SHA1().calculate(for: bytes) + } + + /// Calculate SHA2-224 Digest + /// - parameter bytes: input message + /// - returns: Digest bytes + public static func sha224(_ bytes: Array) -> Array { + self.sha2(bytes, variant: .sha224) + } + + /// Calculate SHA2-256 Digest + /// - parameter bytes: input message + /// - returns: Digest bytes + public static func sha256(_ bytes: Array) -> Array { + self.sha2(bytes, variant: .sha256) + } + + /// Calculate SHA2-384 Digest + /// - parameter bytes: input message + /// - returns: Digest bytes + public static func sha384(_ bytes: Array) -> Array { + self.sha2(bytes, variant: .sha384) + } + + /// Calculate SHA2-512 Digest + /// - parameter bytes: input message + /// - returns: Digest bytes + public static func sha512(_ bytes: Array) -> Array { + self.sha2(bytes, variant: .sha512) + } + + /// Calculate SHA2 Digest + /// - parameter bytes: input message + /// - parameter variant: SHA-2 variant + /// - returns: Digest bytes + public static func sha2(_ bytes: Array, variant: SHA2.Variant) -> Array { + SHA2(variant: variant).calculate(for: bytes) + } + + /// Calculate SHA3 Digest + /// - parameter bytes: input message + /// - parameter variant: SHA-3 variant + /// - returns: Digest bytes + public static func sha3(_ bytes: Array, variant: SHA3.Variant) -> Array { + SHA3(variant: variant).calculate(for: bytes) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/DigestType.swift b/Pods/CryptoSwift/Sources/CryptoSwift/DigestType.swift new file mode 100644 index 0000000..a635c1e --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/DigestType.swift @@ -0,0 +1,18 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +internal protocol DigestType { + func calculate(for bytes: Array) -> Array +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/AES+Foundation.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/AES+Foundation.swift new file mode 100644 index 0000000..088bd90 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/AES+Foundation.swift @@ -0,0 +1,23 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +import Foundation + +extension AES { + /// Initialize with CBC block mode. + public convenience init(key: String, iv: String, padding: Padding = .pkcs7) throws { + try self.init(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: padding) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Array+Foundation.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Array+Foundation.swift new file mode 100644 index 0000000..e65fa51 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Array+Foundation.swift @@ -0,0 +1,32 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +import Foundation + +public extension Array where Element == UInt8 { + func toBase64() -> String? { + Data( self).base64EncodedString() + } + + init(base64: String) { + self.init() + + guard let decodedData = Data(base64Encoded: base64) else { + return + } + + append(contentsOf: decodedData.bytes) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Blowfish+Foundation.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Blowfish+Foundation.swift new file mode 100644 index 0000000..244c466 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Blowfish+Foundation.swift @@ -0,0 +1,23 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +import Foundation + +extension Blowfish { + /// Initialize with CBC block mode. + public convenience init(key: String, iv: String, padding: Padding = .pkcs7) throws { + try self.init(key: key.bytes, blockMode: CBC(iv: iv.bytes), padding: padding) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/ChaCha20+Foundation.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/ChaCha20+Foundation.swift new file mode 100644 index 0000000..f4b7e7e --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/ChaCha20+Foundation.swift @@ -0,0 +1,22 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +import Foundation + +extension ChaCha20 { + public convenience init(key: String, iv: String) throws { + try self.init(key: key.bytes, iv: iv.bytes) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Data+Extension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Data+Extension.swift new file mode 100644 index 0000000..0433ef7 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Data+Extension.swift @@ -0,0 +1,95 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +import Foundation + +extension Data { + /// Two octet checksum as defined in RFC-4880. Sum of all octets, mod 65536 + public func checksum() -> UInt16 { + var s: UInt32 = 0 + let bytesArray = bytes + for i in 0 ..< bytesArray.count { + s = s + UInt32(bytesArray[i]) + } + s = s % 65536 + return UInt16(s) + } + + public func md5() -> Data { + Data( Digest.md5(bytes)) + } + + public func sha1() -> Data { + Data( Digest.sha1(bytes)) + } + + public func sha224() -> Data { + Data( Digest.sha224(bytes)) + } + + public func sha256() -> Data { + Data( Digest.sha256(bytes)) + } + + public func sha384() -> Data { + Data( Digest.sha384(bytes)) + } + + public func sha512() -> Data { + Data( Digest.sha512(bytes)) + } + + public func sha3(_ variant: SHA3.Variant) -> Data { + Data( Digest.sha3(bytes, variant: variant)) + } + + public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> Data { + Data( Checksum.crc32(bytes, seed: seed, reflect: reflect).bytes()) + } + + public func crc32c(seed: UInt32? = nil, reflect: Bool = true) -> Data { + Data( Checksum.crc32c(bytes, seed: seed, reflect: reflect).bytes()) + } + + public func crc16(seed: UInt16? = nil) -> Data { + Data( Checksum.crc16(bytes, seed: seed).bytes()) + } + + public func encrypt(cipher: Cipher) throws -> Data { + Data( try cipher.encrypt(bytes.slice)) + } + + public func decrypt(cipher: Cipher) throws -> Data { + Data( try cipher.decrypt(bytes.slice)) + } + + public func authenticate(with authenticator: Authenticator) throws -> Data { + Data( try authenticator.authenticate(bytes)) + } +} + +extension Data { + public init(hex: String) { + self.init(Array(hex: hex)) + } + + public var bytes: Array { + Array(self) + } + + public func toHexString() -> String { + self.bytes.toHexString() + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/HMAC+Foundation.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/HMAC+Foundation.swift new file mode 100644 index 0000000..77ee890 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/HMAC+Foundation.swift @@ -0,0 +1,22 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +import Foundation + +extension HMAC { + public convenience init(key: String, variant: HMAC.Variant = .md5) throws { + self.init(key: key.bytes, variant: variant) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Rabbit+Foundation.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Rabbit+Foundation.swift new file mode 100644 index 0000000..ff18c36 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Rabbit+Foundation.swift @@ -0,0 +1,26 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +import Foundation + +extension Rabbit { + public convenience init(key: String) throws { + try self.init(key: key.bytes) + } + + public convenience init(key: String, iv: String) throws { + try self.init(key: key.bytes, iv: iv.bytes) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/String+FoundationExtension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/String+FoundationExtension.swift new file mode 100644 index 0000000..b19014d --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/String+FoundationExtension.swift @@ -0,0 +1,41 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +import Foundation + +extension String { + /// Return Base64 back to String + public func decryptBase64ToString(cipher: Cipher) throws -> String { + guard let decodedData = Data(base64Encoded: self, options: []) else { + throw CipherError.decrypt + } + + let decrypted = try decodedData.decrypt(cipher: cipher) + + if let decryptedString = String(data: decrypted, encoding: String.Encoding.utf8) { + return decryptedString + } + + throw CipherError.decrypt + } + + public func decryptBase64(cipher: Cipher) throws -> Array { + guard let decodedData = Data(base64Encoded: self, options: []) else { + throw CipherError.decrypt + } + + return try decodedData.decrypt(cipher: cipher).bytes + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Utils+Foundation.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Utils+Foundation.swift new file mode 100644 index 0000000..e5c0057 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Foundation/Utils+Foundation.swift @@ -0,0 +1,27 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +import Foundation + +func perf(_ text: String, closure: () -> Void) { + let measurementStart = Date() + + closure() + + let measurementStop = Date() + let executionTime = measurementStop.timeIntervalSince(measurementStart) + + print("\(text) \(executionTime)") +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Generics.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Generics.swift new file mode 100644 index 0000000..71203d3 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Generics.swift @@ -0,0 +1,42 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +/// Array of bytes. Caution: don't use directly because generic is slow. +/// +/// - parameter value: integer value +/// - parameter length: length of output array. By default size of value type +/// +/// - returns: Array of bytes +@_specialize(exported: true, where T == Int) +@_specialize(exported: true, where T == UInt) +@_specialize(exported: true, where T == UInt8) +@_specialize(exported: true, where T == UInt16) +@_specialize(exported: true, where T == UInt32) +@_specialize(exported: true, where T == UInt64) +func arrayOfBytes(value: T, length totalBytes: Int = MemoryLayout.size) -> Array { + let valuePointer = UnsafeMutablePointer.allocate(capacity: 1) + valuePointer.pointee = value + + let bytesPointer = UnsafeMutablePointer(OpaquePointer(valuePointer)) + var bytes = Array(repeating: 0, count: totalBytes) + for j in 0...size, totalBytes) { + bytes[totalBytes - 1 - j] = (bytesPointer + j).pointee + } + + valuePointer.deinitialize(count: 1) + valuePointer.deallocate() + + return bytes +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/HKDF.swift b/Pods/CryptoSwift/Sources/CryptoSwift/HKDF.swift new file mode 100644 index 0000000..42e8c91 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/HKDF.swift @@ -0,0 +1,84 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// https://www.ietf.org/rfc/rfc5869.txt +// + +#if canImport(Darwin) + import Darwin +#else + import Glibc +#endif + +/// A key derivation function. +/// +/// HKDF - HMAC-based Extract-and-Expand Key Derivation Function. +public struct HKDF { + public enum Error: Swift.Error { + case invalidInput + case derivedKeyTooLong + } + + private let numBlocks: Int // l + private let dkLen: Int + private let info: Array + private let prk: Array + private let variant: HMAC.Variant + + /// - parameters: + /// - variant: hash variant + /// - salt: optional salt (if not provided, it is set to a sequence of variant.digestLength zeros) + /// - info: optional context and application specific information + /// - keyLength: intended length of derived key + public init(password: Array, salt: Array? = nil, info: Array? = nil, keyLength: Int? = nil /* dkLen */, variant: HMAC.Variant = .sha256) throws { + guard !password.isEmpty else { + throw Error.invalidInput + } + + let dkLen = keyLength ?? variant.digestLength + let keyLengthFinal = Double(dkLen) + let hLen = Double(variant.digestLength) + let numBlocks = Int(ceil(keyLengthFinal / hLen)) // l = ceil(keyLength / hLen) + guard numBlocks <= 255 else { + throw Error.derivedKeyTooLong + } + + /// HKDF-Extract(salt, password) -> PRK + /// - PRK - a pseudo-random key; it is used by calculate() + self.prk = try HMAC(key: salt ?? [], variant: variant).authenticate(password) + self.info = info ?? [] + self.variant = variant + self.dkLen = dkLen + self.numBlocks = numBlocks + } + + public func calculate() throws -> Array { + let hmac = HMAC(key: prk, variant: variant) + var ret = Array() + ret.reserveCapacity(self.numBlocks * self.variant.digestLength) + var value = Array() + for i in 1...self.numBlocks { + value.append(contentsOf: self.info) + value.append(UInt8(i)) + + let bytes = try hmac.authenticate(value) + ret.append(contentsOf: bytes) + + /// update value to use it as input for next iteration + value = bytes + } + return Array(ret.prefix(self.dkLen)) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/HMAC.swift b/Pods/CryptoSwift/Sources/CryptoSwift/HMAC.swift new file mode 100644 index 0000000..4d13749 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/HMAC.swift @@ -0,0 +1,102 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public final class HMAC: Authenticator { + public enum Error: Swift.Error { + case authenticateError + case invalidInput + } + + public enum Variant { + case sha1, sha256, sha384, sha512, md5 + + var digestLength: Int { + switch self { + case .sha1: + return SHA1.digestLength + case .sha256: + return SHA2.Variant.sha256.digestLength + case .sha384: + return SHA2.Variant.sha384.digestLength + case .sha512: + return SHA2.Variant.sha512.digestLength + case .md5: + return MD5.digestLength + } + } + + func calculateHash(_ bytes: Array) -> Array { + switch self { + case .sha1: + return Digest.sha1(bytes) + case .sha256: + return Digest.sha256(bytes) + case .sha384: + return Digest.sha384(bytes) + case .sha512: + return Digest.sha512(bytes) + case .md5: + return Digest.md5(bytes) + } + } + + func blockSize() -> Int { + switch self { + case .md5: + return MD5.blockSize + case .sha1, .sha256: + return 64 + case .sha384, .sha512: + return 128 + } + } + } + + var key: Array + let variant: Variant + + public init(key: Array, variant: HMAC.Variant = .md5) { + self.variant = variant + self.key = key + + if key.count > variant.blockSize() { + let hash = variant.calculateHash(key) + self.key = hash + } + + if key.count < variant.blockSize() { + self.key = ZeroPadding().add(to: key, blockSize: variant.blockSize()) + } + } + + // MARK: Authenticator + + public func authenticate(_ bytes: Array) throws -> Array { + var opad = Array(repeating: 0x5c, count: variant.blockSize()) + for idx in self.key.indices { + opad[idx] = self.key[idx] ^ opad[idx] + } + var ipad = Array(repeating: 0x36, count: variant.blockSize()) + for idx in self.key.indices { + ipad[idx] = self.key[idx] ^ ipad[idx] + } + + let ipadAndMessageHash = self.variant.calculateHash(ipad + bytes) + let result = self.variant.calculateHash(opad + ipadAndMessageHash) + + // return Array(result[0..<10]) // 80 bits + return result + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Int+Extension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Int+Extension.swift new file mode 100644 index 0000000..d8d67ba --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Int+Extension.swift @@ -0,0 +1,31 @@ +// +// CryptoSwift +// +// Created by Marcin Krzyzanowski on 12/08/14. +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +#if canImport(Darwin) + import Darwin +#else + import Glibc +#endif + +extension FixedWidthInteger { + @_transparent + func bytes(totalBytes: Int = MemoryLayout.size) -> Array { + arrayOfBytes(value: self.littleEndian, length: totalBytes) + // TODO: adjust bytes order + // var value = self.littleEndian + // return withUnsafeBytes(of: &value, Array.init).reversed() + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/MD5.swift b/Pods/CryptoSwift/Sources/CryptoSwift/MD5.swift new file mode 100644 index 0000000..217a708 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/MD5.swift @@ -0,0 +1,161 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public final class MD5: DigestType { + static let blockSize: Int = 64 + static let digestLength: Int = 16 // 128 / 8 + fileprivate static let hashInitialValue: Array = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476] + + fileprivate var accumulated = Array() + fileprivate var processedBytesTotalCount: Int = 0 + fileprivate var accumulatedHash: Array = MD5.hashInitialValue + + /** specifies the per-round shift amounts */ + private let s: Array = [ + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + ] + + /** binary integer part of the sines of integers (Radians) */ + private let k: Array = [ + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + ] + + public init() { + } + + public func calculate(for bytes: Array) -> Array { + do { + return try update(withBytes: bytes.slice, isLast: true) + } catch { + fatalError() + } + } + + // mutating currentHash in place is way faster than returning new result + fileprivate func process(block chunk: ArraySlice, currentHash: inout Array) { + assert(chunk.count == 16 * 4) + + // Initialize hash value for this chunk: + var A: UInt32 = currentHash[0] + var B: UInt32 = currentHash[1] + var C: UInt32 = currentHash[2] + var D: UInt32 = currentHash[3] + + var dTemp: UInt32 = 0 + + // Main loop + for j in 0.., isLast: Bool = false) throws -> Array { + self.accumulated += bytes + + if isLast { + let lengthInBits = (processedBytesTotalCount + self.accumulated.count) * 8 + let lengthBytes = lengthInBits.bytes(totalBytes: 64 / 8) // A 64-bit representation of b + + // Step 1. Append padding + bitPadding(to: &self.accumulated, blockSize: MD5.blockSize, allowance: 64 / 8) + + // Step 2. Append Length a 64-bit representation of lengthInBits + self.accumulated += lengthBytes.reversed() + } + + var processedBytes = 0 + for chunk in self.accumulated.batched(by: MD5.blockSize) { + if isLast || (self.accumulated.count - processedBytes) >= MD5.blockSize { + self.process(block: chunk, currentHash: &self.accumulatedHash) + processedBytes += chunk.count + } + } + self.accumulated.removeFirst(processedBytes) + self.processedBytesTotalCount += processedBytes + + // output current hash + var result = Array() + result.reserveCapacity(MD5.digestLength) + + for hElement in self.accumulatedHash { + let hLE = hElement.littleEndian + result += Array(arrayLiteral: UInt8(hLE & 0xff), UInt8((hLE >> 8) & 0xff), UInt8((hLE >> 16) & 0xff), UInt8((hLE >> 24) & 0xff)) + } + + // reset hash value for instance + if isLast { + self.accumulatedHash = MD5.hashInitialValue + } + + return result + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/NoPadding.swift b/Pods/CryptoSwift/Sources/CryptoSwift/NoPadding.swift new file mode 100644 index 0000000..f2a1c46 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/NoPadding.swift @@ -0,0 +1,27 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +struct NoPadding: PaddingProtocol { + init() { + } + + func add(to data: Array, blockSize _: Int) -> Array { + data + } + + func remove(from data: Array, blockSize _: Int?) -> Array { + data + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Operators.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Operators.swift new file mode 100644 index 0000000..a15fe3c --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Operators.swift @@ -0,0 +1,32 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +/* + Bit shifting with overflow protection using overflow operator "&". + Approach is consistent with standard overflow operators &+, &-, &*, &/ + and introduce new overflow operators for shifting: &<<, &>> + + Note: Works with unsigned integers values only + + Usage + + var i = 1 // init + var j = i &<< 2 //shift left + j &<<= 2 //shift left and assign + + @see: https://medium.com/@krzyzanowskim/swiftly-shift-bits-and-protect-yourself-be33016ce071 + + This fuctonality is now implemented as part of Swift 3, SE-0104 https://github.com/apple/swift-evolution/blob/master/proposals/0104-improved-integers.md + */ diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PBKDF1.swift b/Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PBKDF1.swift new file mode 100644 index 0000000..b07baee --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PBKDF1.swift @@ -0,0 +1,87 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public extension PKCS5 { + /// A key derivation function. + /// + /// PBKDF1 is recommended only for compatibility with existing + /// applications since the keys it produces may not be large enough for + /// some applications. + struct PBKDF1 { + public enum Error: Swift.Error { + case invalidInput + case derivedKeyTooLong + } + + public enum Variant { + case md5, sha1 + + var size: Int { + switch self { + case .md5: + return MD5.digestLength + case .sha1: + return SHA1.digestLength + } + } + + fileprivate func calculateHash(_ bytes: Array) -> Array { + switch self { + case .sha1: + return Digest.sha1(bytes) + case .md5: + return Digest.md5(bytes) + } + } + } + + private let iterations: Int // c + private let variant: Variant + private let keyLength: Int + private let t1: Array + + /// - parameters: + /// - salt: salt, an eight-bytes + /// - variant: hash variant + /// - iterations: iteration count, a positive integer + /// - keyLength: intended length of derived key + public init(password: Array, salt: Array, variant: Variant = .sha1, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */ ) throws { + precondition(iterations > 0) + precondition(salt.count == 8) + + let keyLength = keyLength ?? variant.size + + if keyLength > variant.size { + throw Error.derivedKeyTooLong + } + + let t1 = variant.calculateHash(password + salt) + + self.iterations = iterations + self.variant = variant + self.keyLength = keyLength + self.t1 = t1 + } + + /// Apply the underlying hash function Hash for c iterations + public func calculate() -> Array { + var t = self.t1 + for _ in 2...self.iterations { + t = self.variant.calculateHash(t) + } + return Array(t[0.. +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// https://www.ietf.org/rfc/rfc2898.txt +// + +#if canImport(Darwin) + import Darwin +#else + import Glibc +#endif + +public extension PKCS5 { + /// A key derivation function. + /// + /// PBKDF2 - Password-Based Key Derivation Function 2. Key stretching technique. + /// DK = PBKDF2(PRF, Password, Salt, c, dkLen) + struct PBKDF2 { + public enum Error: Swift.Error { + case invalidInput + case derivedKeyTooLong + } + + private let salt: Array // S + fileprivate let iterations: Int // c + private let numBlocks: Int // l + private let dkLen: Int + fileprivate let prf: HMAC + + /// - parameters: + /// - salt: salt + /// - variant: hash variant + /// - iterations: iteration count, a positive integer + /// - keyLength: intended length of derived key + /// - variant: MAC variant. Defaults to SHA256 + public init(password: Array, salt: Array, iterations: Int = 4096 /* c */, keyLength: Int? = nil /* dkLen */, variant: HMAC.Variant = .sha256) throws { + precondition(iterations > 0) + + let prf = HMAC(key: password, variant: variant) + + guard iterations > 0 && !salt.isEmpty else { + throw Error.invalidInput + } + + self.dkLen = keyLength ?? variant.digestLength + let keyLengthFinal = Double(dkLen) + let hLen = Double(prf.variant.digestLength) + if keyLengthFinal > (pow(2, 32) - 1) * hLen { + throw Error.derivedKeyTooLong + } + + self.salt = salt + self.iterations = iterations + self.prf = prf + + self.numBlocks = Int(ceil(Double(keyLengthFinal) / hLen)) // l = ceil(keyLength / hLen) + } + + public func calculate() throws -> Array { + var ret = Array() + ret.reserveCapacity(self.numBlocks * self.prf.variant.digestLength) + for i in 1...self.numBlocks { + // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter + if let value = try calculateBlock(self.salt, blockNum: i) { + ret.append(contentsOf: value) + } + } + return Array(ret.prefix(self.dkLen)) + } + } +} + +private extension PKCS5.PBKDF2 { + func ARR(_ i: Int) -> Array { + var inti = Array(repeating: 0, count: 4) + inti[0] = UInt8((i >> 24) & 0xff) + inti[1] = UInt8((i >> 16) & 0xff) + inti[2] = UInt8((i >> 8) & 0xff) + inti[3] = UInt8(i & 0xff) + return inti + } + + // F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c + // U_1 = PRF (P, S || INT (i)) + func calculateBlock(_ salt: Array, blockNum: Int) throws -> Array? { + guard let u1 = try? prf.authenticate(salt + ARR(blockNum)) else { // blockNum.bytes() is slower + return nil + } + + var u = u1 + var ret = u + if iterations > 1 { + // U_2 = PRF (P, U_1) , + // U_c = PRF (P, U_{c-1}) . + for _ in 2...iterations { + u = try prf.authenticate(u) + for x in 0.. +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// PKCS is a group of public-key cryptography standards devised +// and published by RSA Security Inc, starting in the early 1990s. +// + +public enum PKCS5 { + typealias Padding = PKCS7Padding +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PKCS7.swift b/Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PKCS7.swift new file mode 100644 index 0000000..4100038 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PKCS7.swift @@ -0,0 +1,18 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public enum PKCS7 { + typealias Padding = PKCS7Padding +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PKCS7Padding.swift b/Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PKCS7Padding.swift new file mode 100644 index 0000000..628a298 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/PKCS/PKCS7Padding.swift @@ -0,0 +1,64 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// PKCS is a group of public-key cryptography standards devised +// and published by RSA Security Inc, starting in the early 1990s. +// + +struct PKCS7Padding: PaddingProtocol { + enum Error: Swift.Error { + case invalidPaddingValue + } + + init() { + } + + func add(to bytes: Array, blockSize: Int) -> Array { + let padding = UInt8(blockSize - (bytes.count % blockSize)) + var withPadding = bytes + if padding == 0 { + // If the original data is a multiple of N bytes, then an extra block of bytes with value N is added. + for _ in 0..(arrayLiteral: UInt8(blockSize)) + } + } else { + // The value of each added byte is the number of bytes that are added + for _ in 0..(arrayLiteral: UInt8(padding)) + } + } + return withPadding + } + + func remove(from bytes: Array, blockSize _: Int?) -> Array { + guard !bytes.isEmpty, let lastByte = bytes.last else { + return bytes + } + + assert(!bytes.isEmpty, "Need bytes to remove padding") + + let padding = Int(lastByte) // last byte + let finalLength = bytes.count - padding + + if finalLength < 0 { + return bytes + } + + if padding >= 1 { + return Array(bytes[0.. +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public protocol PaddingProtocol { + func add(to: Array, blockSize: Int) -> Array + func remove(from: Array, blockSize: Int?) -> Array +} + +public enum Padding: PaddingProtocol { + case noPadding, zeroPadding, pkcs7, pkcs5 + + public func add(to: Array, blockSize: Int) -> Array { + switch self { + case .noPadding: + return to // NoPadding().add(to: to, blockSize: blockSize) + case .zeroPadding: + return ZeroPadding().add(to: to, blockSize: blockSize) + case .pkcs7: + return PKCS7.Padding().add(to: to, blockSize: blockSize) + case .pkcs5: + return PKCS5.Padding().add(to: to, blockSize: blockSize) + } + } + + public func remove(from: Array, blockSize: Int?) -> Array { + switch self { + case .noPadding: + return from //NoPadding().remove(from: from, blockSize: blockSize) + case .zeroPadding: + return ZeroPadding().remove(from: from, blockSize: blockSize) + case .pkcs7: + return PKCS7.Padding().remove(from: from, blockSize: blockSize) + case .pkcs5: + return PKCS5.Padding().remove(from: from, blockSize: blockSize) + } + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Poly1305.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Poly1305.swift new file mode 100644 index 0000000..1344c7f --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Poly1305.swift @@ -0,0 +1,165 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-4 +// nacl/crypto_onetimeauth/poly1305/ref/auth.c +// +/// Poly1305 takes a 32-byte, one-time key and a message and produces a 16-byte tag that authenticates the +/// message such that an attacker has a negligible chance of producing a valid tag for an inauthentic message. + +public final class Poly1305: Authenticator { + public enum Error: Swift.Error { + case authenticateError + } + + public static let blockSize: Int = 16 + + private let key: SecureBytes + + /// - parameter key: 32-byte key + public init(key: Array) { + self.key = SecureBytes(bytes: key) + } + + private func squeeze(h: inout Array) { + assert(h.count == 17) + var u: UInt32 = 0 + for j in 0..<16 { + u = u &+ h[j] + h[j] = u & 255 + u = u >> 8 + } + + u = u &+ h[16] + h[16] = u & 3 + u = 5 * (u >> 2) + + for j in 0..<16 { + u = u &+ h[j] + h[j] = u & 255 + u = u >> 8 + } + + u = u &+ h[16] + h[16] = u + } + + private func add(h: inout Array, c: Array) { + assert(h.count == 17 && c.count == 17) + + var u: UInt32 = 0 + for j in 0..<17 { + u = u &+ (h[j] &+ c[j]) + h[j] = u & 255 + u = u >> 8 + } + } + + private func mulmod(h: inout Array, r: Array) { + var hr = Array(repeating: 0, count: 17) + var u: UInt32 = 0 + for i in 0..<17 { + u = 0 + for j in 0...i { + u = u &+ (h[j] * r[i &- j]) + } + for j in (i + 1)..<17 { + u = u &+ (320 * h[j] * r[i &+ 17 &- j]) + } + hr[i] = u + } + h = hr + self.squeeze(h: &h) + } + + private func freeze(h: inout Array) { + let horig = h + self.add(h: &h, c: [5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252]) + let negative = UInt32(bitPattern: -Int32(h[16] >> 7)) + for j in 0..<17 { + h[j] ^= negative & (horig[j] ^ h[j]) + } + } + + /// the key is partitioned into two parts, called "r" and "s" + fileprivate func onetimeauth(message input: Array, key k: Array) -> Array { + // clamp + var r = Array(repeating: 0, count: 17) + var h = Array(repeating: 0, count: 17) + var c = Array(repeating: 0, count: 17) + + r[0] = UInt32(k[0]) + r[1] = UInt32(k[1]) + r[2] = UInt32(k[2]) + r[3] = UInt32(k[3] & 15) + r[4] = UInt32(k[4] & 252) + r[5] = UInt32(k[5]) + r[6] = UInt32(k[6]) + r[7] = UInt32(k[7] & 15) + r[8] = UInt32(k[8] & 252) + r[9] = UInt32(k[9]) + r[10] = UInt32(k[10]) + r[11] = UInt32(k[11] & 15) + r[12] = UInt32(k[12] & 252) + r[13] = UInt32(k[13]) + r[14] = UInt32(k[14]) + r[15] = UInt32(k[15] & 15) + r[16] = 0 + + var inlen = input.count + var inpos = 0 + while inlen > 0 { + for j in 0..) throws -> Array { + self.onetimeauth(message: bytes, key: Array(self.key)) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Rabbit.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Rabbit.swift new file mode 100644 index 0000000..b554297 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Rabbit.swift @@ -0,0 +1,217 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public final class Rabbit: BlockCipher { + public enum Error: Swift.Error { + case invalidKeyOrInitializationVector + } + + /// Size of IV in bytes + public static let ivSize = 64 / 8 + + /// Size of key in bytes + public static let keySize = 128 / 8 + + /// Size of block in bytes + public static let blockSize = 128 / 8 + + public var keySize: Int { + self.key.count + } + + /// Key + private let key: Key + + /// IV (optional) + private let iv: Array? + + /// State variables + private var x = Array(repeating: 0, count: 8) + + /// Counter variables + private var c = Array(repeating: 0, count: 8) + + /// Counter carry + private var p7: UInt32 = 0 + + /// 'a' constants + private var a: Array = [ + 0x4d34d34d, + 0xd34d34d3, + 0x34d34d34, + 0x4d34d34d, + 0xd34d34d3, + 0x34d34d34, + 0x4d34d34d, + 0xd34d34d3 + ] + + // MARK: - Initializers + + public convenience init(key: Array) throws { + try self.init(key: key, iv: nil) + } + + public init(key: Array, iv: Array?) throws { + self.key = Key(bytes: key) + self.iv = iv + + guard key.count == Rabbit.keySize && (iv == nil || iv!.count == Rabbit.ivSize) else { + throw Error.invalidKeyOrInitializationVector + } + } + + // MARK: - + + fileprivate func setup() { + self.p7 = 0 + + // Key divided into 8 subkeys + var k = Array(repeating: 0, count: 8) + for j in 0..<8 { + k[j] = UInt32(self.key[Rabbit.blockSize - (2 * j + 1)]) | (UInt32(self.key[Rabbit.blockSize - (2 * j + 2)]) << 8) + } + + // Initialize state and counter variables from subkeys + for j in 0..<8 { + if j % 2 == 0 { + self.x[j] = (k[(j + 1) % 8] << 16) | k[j] + self.c[j] = (k[(j + 4) % 8] << 16) | k[(j + 5) % 8] + } else { + self.x[j] = (k[(j + 5) % 8] << 16) | k[(j + 4) % 8] + self.c[j] = (k[j] << 16) | k[(j + 1) % 8] + } + } + + // Iterate system four times + self.nextState() + self.nextState() + self.nextState() + self.nextState() + + // Reinitialize counter variables + for j in 0..<8 { + self.c[j] = self.c[j] ^ self.x[(j + 4) % 8] + } + + if let iv = iv { + self.setupIV(iv) + } + } + + private func setupIV(_ iv: Array) { + // 63...56 55...48 47...40 39...32 31...24 23...16 15...8 7...0 IV bits + // 0 1 2 3 4 5 6 7 IV bytes in array + let iv0 = UInt32(bytes: [iv[4], iv[5], iv[6], iv[7]]) + let iv1 = UInt32(bytes: [iv[0], iv[1], iv[4], iv[5]]) + let iv2 = UInt32(bytes: [iv[0], iv[1], iv[2], iv[3]]) + let iv3 = UInt32(bytes: [iv[2], iv[3], iv[6], iv[7]]) + + // Modify the counter state as function of the IV + c[0] = self.c[0] ^ iv0 + self.c[1] = self.c[1] ^ iv1 + self.c[2] = self.c[2] ^ iv2 + self.c[3] = self.c[3] ^ iv3 + self.c[4] = self.c[4] ^ iv0 + self.c[5] = self.c[5] ^ iv1 + self.c[6] = self.c[6] ^ iv2 + self.c[7] = self.c[7] ^ iv3 + + // Iterate system four times + self.nextState() + self.nextState() + self.nextState() + self.nextState() + } + + private func nextState() { + // Before an iteration the counters are incremented + var carry = self.p7 + for j in 0..<8 { + let prev = self.c[j] + self.c[j] = prev &+ self.a[j] &+ carry + carry = prev > self.c[j] ? 1 : 0 // detect overflow + } + self.p7 = carry // save last carry bit + + // Iteration of the system + var newX = Array(repeating: 0, count: 8) + newX[0] = self.g(0) &+ rotateLeft(self.g(7), by: 16) &+ rotateLeft(self.g(6), by: 16) + newX[1] = self.g(1) &+ rotateLeft(self.g(0), by: 8) &+ self.g(7) + newX[2] = self.g(2) &+ rotateLeft(self.g(1), by: 16) &+ rotateLeft(self.g(0), by: 16) + newX[3] = self.g(3) &+ rotateLeft(self.g(2), by: 8) &+ self.g(1) + newX[4] = self.g(4) &+ rotateLeft(self.g(3), by: 16) &+ rotateLeft(self.g(2), by: 16) + newX[5] = self.g(5) &+ rotateLeft(self.g(4), by: 8) &+ self.g(3) + newX[6] = self.g(6) &+ rotateLeft(self.g(5), by: 16) &+ rotateLeft(self.g(4), by: 16) + newX[7] = self.g(7) &+ rotateLeft(self.g(6), by: 8) &+ self.g(5) + self.x = newX + } + + private func g(_ j: Int) -> UInt32 { + let sum = self.x[j] &+ self.c[j] + let square = UInt64(sum) * UInt64(sum) + return UInt32(truncatingIfNeeded: square ^ (square >> 32)) + } + + fileprivate func nextOutput() -> Array { + self.nextState() + + var output16 = Array(repeating: 0, count: Rabbit.blockSize / 2) + output16[7] = UInt16(truncatingIfNeeded: self.x[0]) ^ UInt16(truncatingIfNeeded: self.x[5] >> 16) + output16[6] = UInt16(truncatingIfNeeded: self.x[0] >> 16) ^ UInt16(truncatingIfNeeded: self.x[3]) + output16[5] = UInt16(truncatingIfNeeded: self.x[2]) ^ UInt16(truncatingIfNeeded: self.x[7] >> 16) + output16[4] = UInt16(truncatingIfNeeded: self.x[2] >> 16) ^ UInt16(truncatingIfNeeded: self.x[5]) + output16[3] = UInt16(truncatingIfNeeded: self.x[4]) ^ UInt16(truncatingIfNeeded: self.x[1] >> 16) + output16[2] = UInt16(truncatingIfNeeded: self.x[4] >> 16) ^ UInt16(truncatingIfNeeded: self.x[7]) + output16[1] = UInt16(truncatingIfNeeded: self.x[6]) ^ UInt16(truncatingIfNeeded: self.x[3] >> 16) + output16[0] = UInt16(truncatingIfNeeded: self.x[6] >> 16) ^ UInt16(truncatingIfNeeded: self.x[1]) + + var output8 = Array(repeating: 0, count: Rabbit.blockSize) + for j in 0..> 8) + output8[j * 2 + 1] = UInt8(truncatingIfNeeded: output16[j]) + } + return output8 + } +} + +// MARK: Cipher + +extension Rabbit: Cipher { + public func encrypt(_ bytes: ArraySlice) throws -> Array { + self.setup() + + var result = Array(repeating: 0, count: bytes.count) + var output = self.nextOutput() + var byteIdx = 0 + var outputIdx = 0 + while byteIdx < bytes.count { + if outputIdx == Rabbit.blockSize { + output = self.nextOutput() + outputIdx = 0 + } + + result[byteIdx] = bytes[byteIdx] ^ output[outputIdx] + + byteIdx += 1 + outputIdx += 1 + } + return result + } + + public func decrypt(_ bytes: ArraySlice) throws -> Array { + try self.encrypt(bytes) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/SHA1.swift b/Pods/CryptoSwift/Sources/CryptoSwift/SHA1.swift new file mode 100644 index 0000000..02ecdca --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/SHA1.swift @@ -0,0 +1,145 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +public final class SHA1: DigestType { + static let digestLength: Int = 20 // 160 / 8 + static let blockSize: Int = 64 + fileprivate static let hashInitialValue: ContiguousArray = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0] + + fileprivate var accumulated = Array() + fileprivate var processedBytesTotalCount: Int = 0 + fileprivate var accumulatedHash: ContiguousArray = SHA1.hashInitialValue + + public init() { + } + + public func calculate(for bytes: Array) -> Array { + do { + return try update(withBytes: bytes.slice, isLast: true) + } catch { + return [] + } + } + + fileprivate func process(block chunk: ArraySlice, currentHash hh: inout ContiguousArray) { + // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15, big-endian + // Extend the sixteen 32-bit words into eighty 32-bit words: + let M = UnsafeMutablePointer.allocate(capacity: 80) + M.initialize(repeating: 0, count: 80) + defer { + M.deinitialize(count: 80) + M.deallocate() + } + + for x in 0..<80 { + switch x { + case 0...15: + let start = chunk.startIndex.advanced(by: x * 4) // * MemoryLayout.size + M[x] = UInt32(bytes: chunk, fromIndex: start) + default: + M[x] = rotateLeft(M[x - 3] ^ M[x - 8] ^ M[x - 14] ^ M[x - 16], by: 1) + } + } + + var A = hh[0] + var B = hh[1] + var C = hh[2] + var D = hh[3] + var E = hh[4] + + // Main loop + for j in 0...79 { + var f: UInt32 = 0 + var k: UInt32 = 0 + + switch j { + case 0...19: + f = (B & C) | ((~B) & D) + k = 0x5a827999 + case 20...39: + f = B ^ C ^ D + k = 0x6ed9eba1 + case 40...59: + f = (B & C) | (B & D) | (C & D) + k = 0x8f1bbcdc + case 60...79: + f = B ^ C ^ D + k = 0xca62c1d6 + default: + break + } + + let temp = rotateLeft(A, by: 5) &+ f &+ E &+ M[j] &+ k + E = D + D = C + C = rotateLeft(B, by: 30) + B = A + A = temp + } + + hh[0] = hh[0] &+ A + hh[1] = hh[1] &+ B + hh[2] = hh[2] &+ C + hh[3] = hh[3] &+ D + hh[4] = hh[4] &+ E + } +} + +extension SHA1: Updatable { + @discardableResult + public func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array { + self.accumulated += bytes + + if isLast { + let lengthInBits = (processedBytesTotalCount + self.accumulated.count) * 8 + let lengthBytes = lengthInBits.bytes(totalBytes: 64 / 8) // A 64-bit representation of b + + // Step 1. Append padding + bitPadding(to: &self.accumulated, blockSize: SHA1.blockSize, allowance: 64 / 8) + + // Step 2. Append Length a 64-bit representation of lengthInBits + self.accumulated += lengthBytes + } + + var processedBytes = 0 + for chunk in self.accumulated.batched(by: SHA1.blockSize) { + if isLast || (self.accumulated.count - processedBytes) >= SHA1.blockSize { + self.process(block: chunk, currentHash: &self.accumulatedHash) + processedBytes += chunk.count + } + } + self.accumulated.removeFirst(processedBytes) + self.processedBytesTotalCount += processedBytes + + // output current hash + var result = Array(repeating: 0, count: SHA1.digestLength) + var pos = 0 + for idx in 0..> 24) & 0xff) + result[pos + 1] = UInt8((h >> 16) & 0xff) + result[pos + 2] = UInt8((h >> 8) & 0xff) + result[pos + 3] = UInt8(h & 0xff) + pos += 4 + } + + // reset hash value for instance + if isLast { + self.accumulatedHash = SHA1.hashInitialValue + } + + return result + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/SHA2.swift b/Pods/CryptoSwift/Sources/CryptoSwift/SHA2.swift new file mode 100644 index 0000000..5f326ab --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/SHA2.swift @@ -0,0 +1,345 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// TODO: generic for process32/64 (UInt32/UInt64) +// + +public final class SHA2: DigestType { + let variant: Variant + let size: Int + let blockSize: Int + let digestLength: Int + private let k: Array + + fileprivate var accumulated = Array() + fileprivate var processedBytesTotalCount: Int = 0 + fileprivate var accumulatedHash32 = Array() + fileprivate var accumulatedHash64 = Array() + + public enum Variant: RawRepresentable { + case sha224, sha256, sha384, sha512 + + public var digestLength: Int { + self.rawValue / 8 + } + + public var blockSize: Int { + switch self { + case .sha224, .sha256: + return 64 + case .sha384, .sha512: + return 128 + } + } + + public typealias RawValue = Int + public var rawValue: RawValue { + switch self { + case .sha224: + return 224 + case .sha256: + return 256 + case .sha384: + return 384 + case .sha512: + return 512 + } + } + + public init?(rawValue: RawValue) { + switch rawValue { + case 224: + self = .sha224 + case 256: + self = .sha256 + case 384: + self = .sha384 + case 512: + self = .sha512 + default: + return nil + } + } + + fileprivate var h: Array { + switch self { + case .sha224: + return [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4] + case .sha256: + return [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19] + case .sha384: + return [0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4] + case .sha512: + return [0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179] + } + } + + fileprivate var finalLength: Int { + switch self { + case .sha224: + return 7 + case .sha384: + return 6 + default: + return Int.max + } + } + } + + public init(variant: SHA2.Variant) { + self.variant = variant + switch self.variant { + case .sha224, .sha256: + self.accumulatedHash32 = variant.h.map { UInt32($0) } // FIXME: UInt64 for process64 + self.blockSize = variant.blockSize + self.size = variant.rawValue + self.digestLength = variant.digestLength + self.k = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + ] + case .sha384, .sha512: + self.accumulatedHash64 = variant.h + self.blockSize = variant.blockSize + self.size = variant.rawValue + self.digestLength = variant.digestLength + self.k = [ + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, + 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe, + 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, + 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab, + 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, + 0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, + 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, + 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, + 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c, + 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6, + 0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 + ] + } + } + + public func calculate(for bytes: Array) -> Array { + do { + return try update(withBytes: bytes.slice, isLast: true) + } catch { + return [] + } + } + + fileprivate func process64(block chunk: ArraySlice, currentHash hh: inout Array) { + // break chunk into sixteen 64-bit words M[j], 0 ≤ j ≤ 15, big-endian + // Extend the sixteen 64-bit words into eighty 64-bit words: + let M = UnsafeMutablePointer.allocate(capacity: self.k.count) + M.initialize(repeating: 0, count: self.k.count) + defer { + M.deinitialize(count: self.k.count) + M.deallocate() + } + for x in 0...size + M[x] = UInt64(bytes: chunk, fromIndex: start) + default: + let s0 = rotateRight(M[x - 15], by: 1) ^ rotateRight(M[x - 15], by: 8) ^ (M[x - 15] >> 7) + let s1 = rotateRight(M[x - 2], by: 19) ^ rotateRight(M[x - 2], by: 61) ^ (M[x - 2] >> 6) + M[x] = M[x - 16] &+ s0 &+ M[x - 7] &+ s1 + } + } + + var A = hh[0] + var B = hh[1] + var C = hh[2] + var D = hh[3] + var E = hh[4] + var F = hh[5] + var G = hh[6] + var H = hh[7] + + // Main loop + for j in 0.., currentHash hh: inout Array) { + // break chunk into sixteen 32-bit words M[j], 0 ≤ j ≤ 15, big-endian + // Extend the sixteen 32-bit words into sixty-four 32-bit words: + let M = UnsafeMutablePointer.allocate(capacity: self.k.count) + M.initialize(repeating: 0, count: self.k.count) + defer { + M.deinitialize(count: self.k.count) + M.deallocate() + } + + for x in 0...size + M[x] = UInt32(bytes: chunk, fromIndex: start) + default: + let s0 = rotateRight(M[x - 15], by: 7) ^ rotateRight(M[x - 15], by: 18) ^ (M[x - 15] >> 3) + let s1 = rotateRight(M[x - 2], by: 17) ^ rotateRight(M[x - 2], by: 19) ^ (M[x - 2] >> 10) + M[x] = M[x - 16] &+ s0 &+ M[x - 7] &+ s1 + } + } + + var A = hh[0] + var B = hh[1] + var C = hh[2] + var D = hh[3] + var E = hh[4] + var F = hh[5] + var G = hh[6] + var H = hh[7] + + // Main loop + for j in 0.., isLast: Bool = false) throws -> Array { + self.accumulated += bytes + + if isLast { + let lengthInBits = (processedBytesTotalCount + self.accumulated.count) * 8 + let lengthBytes = lengthInBits.bytes(totalBytes: self.blockSize / 8) // A 64-bit/128-bit representation of b. blockSize fit by accident. + + // Step 1. Append padding + bitPadding(to: &self.accumulated, blockSize: self.blockSize, allowance: self.blockSize / 8) + + // Step 2. Append Length a 64-bit representation of lengthInBits + self.accumulated += lengthBytes + } + + var processedBytes = 0 + for chunk in self.accumulated.batched(by: self.blockSize) { + if isLast || (self.accumulated.count - processedBytes) >= self.blockSize { + switch self.variant { + case .sha224, .sha256: + self.process32(block: chunk, currentHash: &self.accumulatedHash32) + case .sha384, .sha512: + self.process64(block: chunk, currentHash: &self.accumulatedHash64) + } + processedBytes += chunk.count + } + } + self.accumulated.removeFirst(processedBytes) + self.processedBytesTotalCount += processedBytes + + // output current hash + var result = Array(repeating: 0, count: variant.digestLength) + switch self.variant { + case .sha224, .sha256: + var pos = 0 + for idx in 0..> 24) & 0xff) + result[pos + 1] = UInt8((h >> 16) & 0xff) + result[pos + 2] = UInt8((h >> 8) & 0xff) + result[pos + 3] = UInt8(h & 0xff) + pos += 4 + } + case .sha384, .sha512: + var pos = 0 + for idx in 0..> 56) & 0xff) + result[pos + 1] = UInt8((h >> 48) & 0xff) + result[pos + 2] = UInt8((h >> 40) & 0xff) + result[pos + 3] = UInt8((h >> 32) & 0xff) + result[pos + 4] = UInt8((h >> 24) & 0xff) + result[pos + 5] = UInt8((h >> 16) & 0xff) + result[pos + 6] = UInt8((h >> 8) & 0xff) + result[pos + 7] = UInt8(h & 0xff) + pos += 8 + } + } + + // reset hash value for instance + if isLast { + switch self.variant { + case .sha224, .sha256: + self.accumulatedHash32 = self.variant.h.lazy.map { UInt32($0) } // FIXME: UInt64 for process64 + case .sha384, .sha512: + self.accumulatedHash64 = self.variant.h + } + } + + return result + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/SHA3.swift b/Pods/CryptoSwift/Sources/CryptoSwift/SHA3.swift new file mode 100644 index 0000000..fdea882 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/SHA3.swift @@ -0,0 +1,289 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf +// http://keccak.noekeon.org/specs_summary.html +// + +#if canImport(Darwin) + import Darwin +#else + import Glibc +#endif + +public final class SHA3: DigestType { + let round_constants: Array = [ + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, + 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, + 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, + 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, + 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + ] + + public let blockSize: Int + public let digestLength: Int + public let markByte: UInt8 + + fileprivate var accumulated = Array() + fileprivate var accumulatedHash: Array + + public enum Variant { + case sha224, sha256, sha384, sha512, keccak224, keccak256, keccak384, keccak512 + + var digestLength: Int { + 100 - (self.blockSize / 2) + } + + var blockSize: Int { + (1600 - self.outputLength * 2) / 8 + } + + var markByte: UInt8 { + switch self { + case .sha224, .sha256, .sha384, .sha512: + return 0x06 // 0x1F for SHAKE + case .keccak224, .keccak256, .keccak384, .keccak512: + return 0x01 + } + } + + public var outputLength: Int { + switch self { + case .sha224, .keccak224: + return 224 + case .sha256, .keccak256: + return 256 + case .sha384, .keccak384: + return 384 + case .sha512, .keccak512: + return 512 + } + } + } + + public init(variant: SHA3.Variant) { + self.blockSize = variant.blockSize + self.digestLength = variant.digestLength + self.markByte = variant.markByte + self.accumulatedHash = Array(repeating: 0, count: self.digestLength) + } + + public func calculate(for bytes: Array) -> Array { + do { + return try update(withBytes: bytes.slice, isLast: true) + } catch { + return [] + } + } + + /// 1. For all pairs (x,z) such that 0≤x<5 and 0≤z) { + let c = UnsafeMutablePointer.allocate(capacity: 5) + c.initialize(repeating: 0, count: 5) + defer { + c.deinitialize(count: 5) + c.deallocate() + } + let d = UnsafeMutablePointer.allocate(capacity: 5) + d.initialize(repeating: 0, count: 5) + defer { + d.deinitialize(count: 5) + d.deallocate() + } + + for i in 0..<5 { + c[i] = a[i] ^ a[i &+ 5] ^ a[i &+ 10] ^ a[i &+ 15] ^ a[i &+ 20] + } + + d[0] = rotateLeft(c[1], by: 1) ^ c[4] + d[1] = rotateLeft(c[2], by: 1) ^ c[0] + d[2] = rotateLeft(c[3], by: 1) ^ c[1] + d[3] = rotateLeft(c[4], by: 1) ^ c[2] + d[4] = rotateLeft(c[0], by: 1) ^ c[3] + + for i in 0..<5 { + a[i] ^= d[i] + a[i &+ 5] ^= d[i] + a[i &+ 10] ^= d[i] + a[i &+ 15] ^= d[i] + a[i &+ 20] ^= d[i] + } + } + + /// A′[x, y, z]=A[(x &+ 3y) mod 5, x, z] + private func π(_ a: inout Array) { + let a1 = a[1] + a[1] = a[6] + a[6] = a[9] + a[9] = a[22] + a[22] = a[14] + a[14] = a[20] + a[20] = a[2] + a[2] = a[12] + a[12] = a[13] + a[13] = a[19] + a[19] = a[23] + a[23] = a[15] + a[15] = a[4] + a[4] = a[24] + a[24] = a[21] + a[21] = a[8] + a[8] = a[16] + a[16] = a[5] + a[5] = a[3] + a[3] = a[18] + a[18] = a[17] + a[17] = a[11] + a[11] = a[7] + a[7] = a[10] + a[10] = a1 + } + + /// For all triples (x, y, z) such that 0≤x<5, 0≤y<5, and 0≤z) { + for i in stride(from: 0, to: 25, by: 5) { + let a0 = a[0 &+ i] + let a1 = a[1 &+ i] + a[0 &+ i] ^= ~a1 & a[2 &+ i] + a[1 &+ i] ^= ~a[2 &+ i] & a[3 &+ i] + a[2 &+ i] ^= ~a[3 &+ i] & a[4 &+ i] + a[3 &+ i] ^= ~a[4 &+ i] & a0 + a[4 &+ i] ^= ~a0 & a1 + } + } + + private func ι(_ a: inout Array, round: Int) { + a[0] ^= self.round_constants[round] + } + + fileprivate func process(block chunk: ArraySlice, currentHash hh: inout Array) { + // expand + hh[0] ^= chunk[0].littleEndian + hh[1] ^= chunk[1].littleEndian + hh[2] ^= chunk[2].littleEndian + hh[3] ^= chunk[3].littleEndian + hh[4] ^= chunk[4].littleEndian + hh[5] ^= chunk[5].littleEndian + hh[6] ^= chunk[6].littleEndian + hh[7] ^= chunk[7].littleEndian + hh[8] ^= chunk[8].littleEndian + if self.blockSize > 72 { // 72 / 8, sha-512 + hh[9] ^= chunk[9].littleEndian + hh[10] ^= chunk[10].littleEndian + hh[11] ^= chunk[11].littleEndian + hh[12] ^= chunk[12].littleEndian + if self.blockSize > 104 { // 104 / 8, sha-384 + hh[13] ^= chunk[13].littleEndian + hh[14] ^= chunk[14].littleEndian + hh[15] ^= chunk[15].littleEndian + hh[16] ^= chunk[16].littleEndian + if self.blockSize > 136 { // 136 / 8, sha-256 + hh[17] ^= chunk[17].littleEndian + // FULL_SHA3_FAMILY_SUPPORT + if self.blockSize > 144 { // 144 / 8, sha-224 + hh[18] ^= chunk[18].littleEndian + hh[19] ^= chunk[19].littleEndian + hh[20] ^= chunk[20].littleEndian + hh[21] ^= chunk[21].littleEndian + hh[22] ^= chunk[22].littleEndian + hh[23] ^= chunk[23].littleEndian + hh[24] ^= chunk[24].littleEndian + } + } + } + } + + // Keccak-f + for round in 0..<24 { + self.θ(&hh) + + hh[1] = rotateLeft(hh[1], by: 1) + hh[2] = rotateLeft(hh[2], by: 62) + hh[3] = rotateLeft(hh[3], by: 28) + hh[4] = rotateLeft(hh[4], by: 27) + hh[5] = rotateLeft(hh[5], by: 36) + hh[6] = rotateLeft(hh[6], by: 44) + hh[7] = rotateLeft(hh[7], by: 6) + hh[8] = rotateLeft(hh[8], by: 55) + hh[9] = rotateLeft(hh[9], by: 20) + hh[10] = rotateLeft(hh[10], by: 3) + hh[11] = rotateLeft(hh[11], by: 10) + hh[12] = rotateLeft(hh[12], by: 43) + hh[13] = rotateLeft(hh[13], by: 25) + hh[14] = rotateLeft(hh[14], by: 39) + hh[15] = rotateLeft(hh[15], by: 41) + hh[16] = rotateLeft(hh[16], by: 45) + hh[17] = rotateLeft(hh[17], by: 15) + hh[18] = rotateLeft(hh[18], by: 21) + hh[19] = rotateLeft(hh[19], by: 8) + hh[20] = rotateLeft(hh[20], by: 18) + hh[21] = rotateLeft(hh[21], by: 2) + hh[22] = rotateLeft(hh[22], by: 61) + hh[23] = rotateLeft(hh[23], by: 56) + hh[24] = rotateLeft(hh[24], by: 14) + + self.π(&hh) + self.χ(&hh) + self.ι(&hh, round: round) + } + } +} + +extension SHA3: Updatable { + public func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array { + self.accumulated += bytes + + if isLast { + // Add padding + let markByteIndex = self.accumulated.count + + // We need to always pad the input. Even if the input is a multiple of blockSize. + let r = self.blockSize * 8 + let q = (r / 8) - (accumulated.count % (r / 8)) + self.accumulated += Array(repeating: 0, count: q) + + self.accumulated[markByteIndex] |= self.markByte + self.accumulated[self.accumulated.count - 1] |= 0x80 + } + + var processedBytes = 0 + for chunk in self.accumulated.batched(by: self.blockSize) { + if isLast || (self.accumulated.count - processedBytes) >= self.blockSize { + self.process(block: chunk.toUInt64Array().slice, currentHash: &self.accumulatedHash) + processedBytes += chunk.count + } + } + self.accumulated.removeFirst(processedBytes) + + // TODO: verify performance, reduce vs for..in + let result = self.accumulatedHash.reduce(Array()) { (result, value) -> Array in + result + value.bigEndian.bytes() + } + + // reset hash value for instance + if isLast { + self.accumulatedHash = Array(repeating: 0, count: self.digestLength) + } + + return Array(result[0.. +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +// +// https://tools.ietf.org/html/rfc7914 +// + +/// Implementation of the scrypt key derivation function. +public final class Scrypt { + enum Error: Swift.Error { + case nIsTooLarge + case rIsTooLarge + case nMustBeAPowerOf2GreaterThan1 + case invalidInput + } + + /// Configuration parameters. + private let salt: SecureBytes + private let password: SecureBytes + private let blocksize: Int // 128 * r + private let salsaBlock = UnsafeMutableRawPointer.allocate(byteCount: 64, alignment: 64) + private let dkLen: Int + private let N: Int + private let r: Int + private let p: Int + + /// - parameters: + /// - password: password + /// - salt: salt + /// - dkLen: output length + /// - N: determines extra memory used + /// - r: determines a block size + /// - p: determines parallelicity degree + public init(password: Array, salt: Array, dkLen: Int, N: Int, r: Int, p: Int) throws { + precondition(dkLen > 0) + precondition(N > 0) + precondition(r > 0) + precondition(p > 0) + + guard !(N < 2 || (N & (N - 1)) != 0) else { throw Error.nMustBeAPowerOf2GreaterThan1 } + + guard N <= .max / 128 / r else { throw Error.nIsTooLarge } + guard r <= .max / 128 / p else { throw Error.rIsTooLarge } + + guard !salt.isEmpty else { + throw Error.invalidInput + } + + self.blocksize = 128 * r + self.N = N + self.r = r + self.p = p + self.password = SecureBytes(bytes: password) + self.salt = SecureBytes(bytes: salt) + self.dkLen = dkLen + } + + /// Runs the key derivation function with a specific password. + public func calculate() throws -> [UInt8] { + // Allocate memory (as bytes for now) for further use in mixing steps + let B = UnsafeMutableRawPointer.allocate(byteCount: 128 * self.r * self.p, alignment: 64) + let XY = UnsafeMutableRawPointer.allocate(byteCount: 256 * self.r + 64, alignment: 64) + let V = UnsafeMutableRawPointer.allocate(byteCount: 128 * self.r * self.N, alignment: 64) + + // Deallocate memory when done + defer { + B.deallocate() + XY.deallocate() + V.deallocate() + } + + /* 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen) */ + // Expand the initial key + let barray = try PKCS5.PBKDF2(password: Array(self.password), salt: Array(self.salt), iterations: 1, keyLength: self.p * 128 * self.r, variant: .sha256).calculate() + barray.withUnsafeBytes { p in + B.copyMemory(from: p.baseAddress!, byteCount: barray.count) + } + + /* 2: for i = 0 to p - 1 do */ + // do the mixing + for i in 0 ..< self.p { + /* 3: B_i <-- MF(B_i, N) */ + smix(B + i * 128 * self.r, V.assumingMemoryBound(to: UInt32.self), XY.assumingMemoryBound(to: UInt32.self)) + } + + /* 5: DK <-- PBKDF2(P, B, 1, dkLen) */ + let pointer = B.assumingMemoryBound(to: UInt8.self) + let bufferPointer = UnsafeBufferPointer(start: pointer, count: p * 128 * self.r) + let block = [UInt8](bufferPointer) + return try PKCS5.PBKDF2(password: Array(self.password), salt: block, iterations: 1, keyLength: self.dkLen, variant: .sha256).calculate() + } +} + +private extension Scrypt { + /// Computes `B = SMix_r(B, N)`. + /// + /// The input `block` must be `128*r` bytes in length; the temporary storage `v` must be `128*r*n` bytes in length; + /// the temporary storage `xy` must be `256*r + 64` bytes in length. The arrays `block`, `v`, and `xy` must be + /// aligned to a multiple of 64 bytes. + @inline(__always) func smix(_ block: UnsafeMutableRawPointer, _ v: UnsafeMutablePointer, _ xy: UnsafeMutablePointer) { + let X = xy + let Y = xy + 32 * self.r + let Z = xy + 64 * self.r + + /* 1: X <-- B */ + let typedBlock = block.assumingMemoryBound(to: UInt32.self) + X.assign(from: typedBlock, count: 32 * self.r) + + /* 2: for i = 0 to N - 1 do */ + for i in stride(from: 0, to: self.N, by: 2) { + /* 3: V_i <-- X */ + UnsafeMutableRawPointer(v + i * (32 * self.r)).copyMemory(from: X, byteCount: 128 * self.r) + + /* 4: X <-- H(X) */ + self.blockMixSalsa8(X, Y, Z) + + /* 3: V_i <-- X */ + UnsafeMutableRawPointer(v + (i + 1) * (32 * self.r)).copyMemory(from: Y, byteCount: 128 * self.r) + + /* 4: X <-- H(X) */ + self.blockMixSalsa8(Y, X, Z) + } + + /* 6: for i = 0 to N - 1 do */ + for _ in stride(from: 0, to: self.N, by: 2) { + /* + 7: j <-- Integerify (X) mod N + where Integerify (B[0] ... B[2 * r - 1]) is defined + as the result of interpreting B[2 * r - 1] as a little-endian integer. + */ + var j = Int(integerify(X) & UInt64(self.N - 1)) + + /* 8: X <-- H(X \xor V_j) */ + self.blockXor(X, v + j * 32 * self.r, 128 * self.r) + self.blockMixSalsa8(X, Y, Z) + + /* 7: j <-- Integerify(X) mod N */ + j = Int(self.integerify(Y) & UInt64(self.N - 1)) + + /* 8: X <-- H(X \xor V_j) */ + self.blockXor(Y, v + j * 32 * self.r, 128 * self.r) + self.blockMixSalsa8(Y, X, Z) + } + + /* 10: B' <-- X */ + for k in 0 ..< 32 * self.r { + UnsafeMutableRawPointer(block + 4 * k).storeBytes(of: X[k], as: UInt32.self) + } + } + + /// Returns the result of parsing `B_{2r-1}` as a little-endian integer. + @inline(__always) func integerify(_ block: UnsafeRawPointer) -> UInt64 { + let bi = block + (2 * self.r - 1) * 64 + return bi.load(as: UInt64.self).littleEndian + } + + /// Compute `bout = BlockMix_{salsa20/8, r}(bin)`. + /// + /// The input `bin` must be `128*r` bytes in length; the output `bout` must also be the same size. The temporary + /// space `x` must be 64 bytes. + @inline(__always) func blockMixSalsa8(_ bin: UnsafePointer, _ bout: UnsafeMutablePointer, _ x: UnsafeMutablePointer) { + /* 1: X <-- B_{2r - 1} */ + UnsafeMutableRawPointer(x).copyMemory(from: bin + (2 * self.r - 1) * 16, byteCount: 64) + + /* 2: for i = 0 to 2r - 1 do */ + for i in stride(from: 0, to: 2 * self.r, by: 2) { + /* 3: X <-- H(X \xor B_i) */ + self.blockXor(x, bin + i * 16, 64) + self.salsa20_8_typed(x) + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + UnsafeMutableRawPointer(bout + i * 8).copyMemory(from: x, byteCount: 64) + + /* 3: X <-- H(X \xor B_i) */ + self.blockXor(x, bin + i * 16 + 16, 64) + self.salsa20_8_typed(x) + + /* 4: Y_i <-- X */ + /* 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1}) */ + UnsafeMutableRawPointer(bout + i * 8 + self.r * 16).copyMemory(from: x, byteCount: 64) + } + } + + @inline(__always) func salsa20_8_typed(_ block: UnsafeMutablePointer) { + self.salsaBlock.copyMemory(from: UnsafeRawPointer(block), byteCount: 64) + let salsaBlockTyped = self.salsaBlock.assumingMemoryBound(to: UInt32.self) + + for _ in stride(from: 0, to: 8, by: 2) { + salsaBlockTyped[4] ^= rotateLeft(salsaBlockTyped[0] &+ salsaBlockTyped[12], by: 7) + salsaBlockTyped[8] ^= rotateLeft(salsaBlockTyped[4] &+ salsaBlockTyped[0], by: 9) + salsaBlockTyped[12] ^= rotateLeft(salsaBlockTyped[8] &+ salsaBlockTyped[4], by: 13) + salsaBlockTyped[0] ^= rotateLeft(salsaBlockTyped[12] &+ salsaBlockTyped[8], by: 18) + + salsaBlockTyped[9] ^= rotateLeft(salsaBlockTyped[5] &+ salsaBlockTyped[1], by: 7) + salsaBlockTyped[13] ^= rotateLeft(salsaBlockTyped[9] &+ salsaBlockTyped[5], by: 9) + salsaBlockTyped[1] ^= rotateLeft(salsaBlockTyped[13] &+ salsaBlockTyped[9], by: 13) + salsaBlockTyped[5] ^= rotateLeft(salsaBlockTyped[1] &+ salsaBlockTyped[13], by: 18) + + salsaBlockTyped[14] ^= rotateLeft(salsaBlockTyped[10] &+ salsaBlockTyped[6], by: 7) + salsaBlockTyped[2] ^= rotateLeft(salsaBlockTyped[14] &+ salsaBlockTyped[10], by: 9) + salsaBlockTyped[6] ^= rotateLeft(salsaBlockTyped[2] &+ salsaBlockTyped[14], by: 13) + salsaBlockTyped[10] ^= rotateLeft(salsaBlockTyped[6] &+ salsaBlockTyped[2], by: 18) + + salsaBlockTyped[3] ^= rotateLeft(salsaBlockTyped[15] &+ salsaBlockTyped[11], by: 7) + salsaBlockTyped[7] ^= rotateLeft(salsaBlockTyped[3] &+ salsaBlockTyped[15], by: 9) + salsaBlockTyped[11] ^= rotateLeft(salsaBlockTyped[7] &+ salsaBlockTyped[3], by: 13) + salsaBlockTyped[15] ^= rotateLeft(salsaBlockTyped[11] &+ salsaBlockTyped[7], by: 18) + + salsaBlockTyped[1] ^= rotateLeft(salsaBlockTyped[0] &+ salsaBlockTyped[3], by: 7) + salsaBlockTyped[2] ^= rotateLeft(salsaBlockTyped[1] &+ salsaBlockTyped[0], by: 9) + salsaBlockTyped[3] ^= rotateLeft(salsaBlockTyped[2] &+ salsaBlockTyped[1], by: 13) + salsaBlockTyped[0] ^= rotateLeft(salsaBlockTyped[3] &+ salsaBlockTyped[2], by: 18) + + salsaBlockTyped[6] ^= rotateLeft(salsaBlockTyped[5] &+ salsaBlockTyped[4], by: 7) + salsaBlockTyped[7] ^= rotateLeft(salsaBlockTyped[6] &+ salsaBlockTyped[5], by: 9) + salsaBlockTyped[4] ^= rotateLeft(salsaBlockTyped[7] &+ salsaBlockTyped[6], by: 13) + salsaBlockTyped[5] ^= rotateLeft(salsaBlockTyped[4] &+ salsaBlockTyped[7], by: 18) + + salsaBlockTyped[11] ^= rotateLeft(salsaBlockTyped[10] &+ salsaBlockTyped[9], by: 7) + salsaBlockTyped[8] ^= rotateLeft(salsaBlockTyped[11] &+ salsaBlockTyped[10], by: 9) + salsaBlockTyped[9] ^= rotateLeft(salsaBlockTyped[8] &+ salsaBlockTyped[11], by: 13) + salsaBlockTyped[10] ^= rotateLeft(salsaBlockTyped[9] &+ salsaBlockTyped[8], by: 18) + + salsaBlockTyped[12] ^= rotateLeft(salsaBlockTyped[15] &+ salsaBlockTyped[14], by: 7) + salsaBlockTyped[13] ^= rotateLeft(salsaBlockTyped[12] &+ salsaBlockTyped[15], by: 9) + salsaBlockTyped[14] ^= rotateLeft(salsaBlockTyped[13] &+ salsaBlockTyped[12], by: 13) + salsaBlockTyped[15] ^= rotateLeft(salsaBlockTyped[14] &+ salsaBlockTyped[13], by: 18) + } + for i in 0 ..< 16 { + block[i] = block[i] &+ salsaBlockTyped[i] + } + } + + @inline(__always) func blockXor(_ dest: UnsafeMutableRawPointer, _ src: UnsafeRawPointer, _ len: Int) { + let D = dest.assumingMemoryBound(to: UInt64.self) + let S = src.assumingMemoryBound(to: UInt64.self) + let L = len / MemoryLayout.size + + for i in 0 ..< L { + D[i] ^= S[i] + } + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/SecureBytes.swift b/Pods/CryptoSwift/Sources/CryptoSwift/SecureBytes.swift new file mode 100644 index 0000000..849400a --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/SecureBytes.swift @@ -0,0 +1,77 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +#if canImport(Darwin) + import Darwin +#else + import Glibc +#endif + +typealias Key = SecureBytes + +/// Keeps bytes in memory. Because this is class, bytes are not copied +/// and memory area is locked as long as referenced, then unlocked on deinit +final class SecureBytes { + private let bytes: Array + let count: Int + + init(bytes: Array) { + self.bytes = bytes + self.count = bytes.count + self.bytes.withUnsafeBufferPointer { (pointer) -> Void in + mlock(pointer.baseAddress, pointer.count) + } + } + + deinit { + self.bytes.withUnsafeBufferPointer { (pointer) -> Void in + munlock(pointer.baseAddress, pointer.count) + } + } +} + +extension SecureBytes: Collection { + typealias Index = Int + + var endIndex: Int { + self.bytes.endIndex + } + + var startIndex: Int { + self.bytes.startIndex + } + + subscript(position: Index) -> UInt8 { + self.bytes[position] + } + + subscript(bounds: Range) -> ArraySlice { + self.bytes[bounds] + } + + func formIndex(after i: inout Int) { + self.bytes.formIndex(after: &i) + } + + func index(after i: Int) -> Int { + self.bytes.index(after: i) + } +} + +extension SecureBytes: ExpressibleByArrayLiteral { + public convenience init(arrayLiteral elements: UInt8...) { + self.init(bytes: elements) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/StreamDecryptor.swift b/Pods/CryptoSwift/Sources/CryptoSwift/StreamDecryptor.swift new file mode 100644 index 0000000..670ff99 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/StreamDecryptor.swift @@ -0,0 +1,79 @@ +// CryptoSwift +// +// Copyright (C) 2014-2018 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +final class StreamDecryptor: Cryptor, Updatable { + private let blockSize: Int + private var worker: CipherModeWorker + private let padding: Padding + private var accumulated = Array() + + private var lastBlockRemainder = 0 + + init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws { + self.blockSize = blockSize + self.padding = padding + self.worker = worker + } + + // MARK: Updatable + + public func update(withBytes bytes: ArraySlice, isLast: Bool) throws -> Array { + self.accumulated += bytes + + let toProcess = self.accumulated.prefix(max(self.accumulated.count - self.worker.additionalBufferSize, 0)) + + if var finalizingWorker = worker as? FinalizingDecryptModeWorker, isLast == true { + // will truncate suffix if needed + try finalizingWorker.willDecryptLast(bytes: self.accumulated.slice) + } + + var processedBytesCount = 0 + var plaintext = Array(reserveCapacity: bytes.count + self.worker.additionalBufferSize) + for chunk in toProcess.batched(by: self.blockSize) { + plaintext += self.worker.decrypt(block: chunk) + processedBytesCount += chunk.count + } + + if var finalizingWorker = worker as? FinalizingDecryptModeWorker, isLast == true { + plaintext = Array(try finalizingWorker.didDecryptLast(bytes: plaintext.slice)) + } + + // omit unecessary calculation if not needed + if self.padding != .noPadding { + self.lastBlockRemainder = plaintext.count.quotientAndRemainder(dividingBy: self.blockSize).remainder + } + + if isLast { + // CTR doesn't need padding. Really. Add padding to the last block if really want. but... don't. + plaintext = self.padding.remove(from: plaintext, blockSize: self.blockSize - self.lastBlockRemainder) + } + + self.accumulated.removeFirst(processedBytesCount) // super-slow + + if var finalizingWorker = worker as? FinalizingDecryptModeWorker, isLast == true { + plaintext = Array(try finalizingWorker.finalize(decrypt: plaintext.slice)) + } + + return plaintext + } + + public func seek(to position: Int) throws { + guard var worker = self.worker as? SeekableModeWorker else { + fatalError("Not supported") + } + + try worker.seek(to: position) + self.worker = worker + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/StreamEncryptor.swift b/Pods/CryptoSwift/Sources/CryptoSwift/StreamEncryptor.swift new file mode 100644 index 0000000..50d4106 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/StreamEncryptor.swift @@ -0,0 +1,57 @@ +// CryptoSwift +// +// Copyright (C) 2014-2018 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +final class StreamEncryptor: Cryptor, Updatable { + private let blockSize: Int + private var worker: CipherModeWorker + private let padding: Padding + + private var lastBlockRemainder = 0 + + init(blockSize: Int, padding: Padding, _ worker: CipherModeWorker) throws { + self.blockSize = blockSize + self.padding = padding + self.worker = worker + } + + // MARK: Updatable + + public func update(withBytes bytes: ArraySlice, isLast: Bool) throws -> Array { + var accumulated = Array(bytes) + if isLast { + // CTR doesn't need padding. Really. Add padding to the last block if really want. but... don't. + accumulated = self.padding.add(to: accumulated, blockSize: self.blockSize - self.lastBlockRemainder) + } + + var encrypted = Array(reserveCapacity: bytes.count) + for chunk in accumulated.batched(by: self.blockSize) { + encrypted += self.worker.encrypt(block: chunk) + } + + // omit unecessary calculation if not needed + if self.padding != .noPadding { + self.lastBlockRemainder = encrypted.count.quotientAndRemainder(dividingBy: self.blockSize).remainder + } + + if var finalizingWorker = worker as? FinalizingEncryptModeWorker, isLast == true { + encrypted = Array(try finalizingWorker.finalize(encrypt: encrypted.slice)) + } + + return encrypted + } + + func seek(to: Int) throws { + fatalError("Not supported") + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/String+Extension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/String+Extension.swift new file mode 100644 index 0000000..49cff61 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/String+Extension.swift @@ -0,0 +1,81 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +/** String extension */ +extension String { + public var bytes: Array { + data(using: String.Encoding.utf8, allowLossyConversion: true)?.bytes ?? Array(utf8) + } + + public func md5() -> String { + self.bytes.md5().toHexString() + } + + public func sha1() -> String { + self.bytes.sha1().toHexString() + } + + public func sha224() -> String { + self.bytes.sha224().toHexString() + } + + public func sha256() -> String { + self.bytes.sha256().toHexString() + } + + public func sha384() -> String { + self.bytes.sha384().toHexString() + } + + public func sha512() -> String { + self.bytes.sha512().toHexString() + } + + public func sha3(_ variant: SHA3.Variant) -> String { + self.bytes.sha3(variant).toHexString() + } + + public func crc32(seed: UInt32? = nil, reflect: Bool = true) -> String { + self.bytes.crc32(seed: seed, reflect: reflect).bytes().toHexString() + } + + public func crc32c(seed: UInt32? = nil, reflect: Bool = true) -> String { + self.bytes.crc32c(seed: seed, reflect: reflect).bytes().toHexString() + } + + public func crc16(seed: UInt16? = nil) -> String { + self.bytes.crc16(seed: seed).bytes().toHexString() + } + + /// - parameter cipher: Instance of `Cipher` + /// - returns: hex string of bytes + public func encrypt(cipher: Cipher) throws -> String { + try self.bytes.encrypt(cipher: cipher).toHexString() + } + + /// - parameter cipher: Instance of `Cipher` + /// - returns: base64 encoded string of encrypted bytes + public func encryptToBase64(cipher: Cipher) throws -> String? { + try self.bytes.encrypt(cipher: cipher).toBase64() + } + + // decrypt() does not make sense for String + + /// - parameter authenticator: Instance of `Authenticator` + /// - returns: hex string of string + public func authenticate(with authenticator: A) throws -> String { + try self.bytes.authenticate(with: authenticator).toHexString() + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/UInt128.swift b/Pods/CryptoSwift/Sources/CryptoSwift/UInt128.swift new file mode 100644 index 0000000..8e3c246 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/UInt128.swift @@ -0,0 +1,90 @@ +// +// UInt128.swift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +import Foundation + +struct UInt128: Equatable, ExpressibleByIntegerLiteral { + let i: (a: UInt64, b: UInt64) + + typealias IntegerLiteralType = UInt64 + + init(integerLiteral value: IntegerLiteralType) { + self = UInt128(value) + } + + init(_ raw: Array) { + self = raw.prefix(MemoryLayout.stride).withUnsafeBytes({ (rawBufferPointer) -> UInt128 in + let arr = rawBufferPointer.bindMemory(to: UInt64.self) + return UInt128((arr[0].bigEndian, arr[1].bigEndian)) + }) + } + + init(_ raw: ArraySlice) { + self.init(Array(raw)) + } + + init(_ i: (a: UInt64, b: UInt64)) { + self.i = i + } + + init(a: UInt64, b: UInt64) { + self.init((a, b)) + } + + init(_ b: UInt64) { + self.init((0, b)) + } + + // Bytes + var bytes: Array { + var at = self.i.a.bigEndian + var bt = self.i.b.bigEndian + + let ar = Data(bytes: &at, count: MemoryLayout.size(ofValue: at)) + let br = Data(bytes: &bt, count: MemoryLayout.size(ofValue: bt)) + + var result = Data() + result.append(ar) + result.append(br) + return result.bytes + } + + static func ^ (n1: UInt128, n2: UInt128) -> UInt128 { + UInt128((n1.i.a ^ n2.i.a, n1.i.b ^ n2.i.b)) + } + + static func & (n1: UInt128, n2: UInt128) -> UInt128 { + UInt128((n1.i.a & n2.i.a, n1.i.b & n2.i.b)) + } + + static func >> (value: UInt128, by: Int) -> UInt128 { + var result = value + for _ in 0..> 1 + let b = result.i.b >> 1 + ((result.i.a & 1) << 63) + result = UInt128((a, b)) + } + return result + } + + // Equatable. + static func == (lhs: UInt128, rhs: UInt128) -> Bool { + lhs.i == rhs.i + } + + static func != (lhs: UInt128, rhs: UInt128) -> Bool { + !(lhs == rhs) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/UInt16+Extension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/UInt16+Extension.swift new file mode 100644 index 0000000..7a097ca --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/UInt16+Extension.swift @@ -0,0 +1,37 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +/** array of bytes */ +extension UInt16 { + @_specialize(exported: true, where T == ArraySlice) + init(bytes: T) where T.Element == UInt8, T.Index == Int { + self = UInt16(bytes: bytes, fromIndex: bytes.startIndex) + } + + @_specialize(exported: true, where T == ArraySlice) + init(bytes: T, fromIndex index: T.Index) where T.Element == UInt8, T.Index == Int { + if bytes.isEmpty { + self = 0 + return + } + + let count = bytes.count + + let val0 = count > 0 ? UInt16(bytes[index.advanced(by: 0)]) << 8 : 0 + let val1 = count > 1 ? UInt16(bytes[index.advanced(by: 1)]) : 0 + + self = val0 | val1 + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/UInt32+Extension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/UInt32+Extension.swift new file mode 100644 index 0000000..b0c5fa5 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/UInt32+Extension.swift @@ -0,0 +1,48 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +#if canImport(Darwin) + import Darwin +#else + import Glibc +#endif + +protocol _UInt32Type {} +extension UInt32: _UInt32Type {} + +/** array of bytes */ +extension UInt32 { + @_specialize(exported: true, where T == ArraySlice) + init(bytes: T) where T.Element == UInt8, T.Index == Int { + self = UInt32(bytes: bytes, fromIndex: bytes.startIndex) + } + + @_specialize(exported: true, where T == ArraySlice) + init(bytes: T, fromIndex index: T.Index) where T.Element == UInt8, T.Index == Int { + if bytes.isEmpty { + self = 0 + return + } + + let count = bytes.count + + let val0 = count > 0 ? UInt32(bytes[index.advanced(by: 0)]) << 24 : 0 + let val1 = count > 1 ? UInt32(bytes[index.advanced(by: 1)]) << 16 : 0 + let val2 = count > 2 ? UInt32(bytes[index.advanced(by: 2)]) << 8 : 0 + let val3 = count > 3 ? UInt32(bytes[index.advanced(by: 3)]) : 0 + + self = val0 | val1 | val2 | val3 + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/UInt64+Extension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/UInt64+Extension.swift new file mode 100644 index 0000000..46a9b73 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/UInt64+Extension.swift @@ -0,0 +1,43 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +/** array of bytes */ +extension UInt64 { + @_specialize(exported: true, where T == ArraySlice) + init(bytes: T) where T.Element == UInt8, T.Index == Int { + self = UInt64(bytes: bytes, fromIndex: bytes.startIndex) + } + + @_specialize(exported: true, where T == ArraySlice) + init(bytes: T, fromIndex index: T.Index) where T.Element == UInt8, T.Index == Int { + if bytes.isEmpty { + self = 0 + return + } + + let count = bytes.count + + let val0 = count > 0 ? UInt64(bytes[index.advanced(by: 0)]) << 56 : 0 + let val1 = count > 1 ? UInt64(bytes[index.advanced(by: 1)]) << 48 : 0 + let val2 = count > 2 ? UInt64(bytes[index.advanced(by: 2)]) << 40 : 0 + let val3 = count > 3 ? UInt64(bytes[index.advanced(by: 3)]) << 32 : 0 + let val4 = count > 4 ? UInt64(bytes[index.advanced(by: 4)]) << 24 : 0 + let val5 = count > 5 ? UInt64(bytes[index.advanced(by: 5)]) << 16 : 0 + let val6 = count > 6 ? UInt64(bytes[index.advanced(by: 6)]) << 8 : 0 + let val7 = count > 7 ? UInt64(bytes[index.advanced(by: 7)]) : 0 + + self = val0 | val1 | val2 | val3 | val4 | val5 | val6 | val7 + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/UInt8+Extension.swift b/Pods/CryptoSwift/Sources/CryptoSwift/UInt8+Extension.swift new file mode 100644 index 0000000..b4de65d --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/UInt8+Extension.swift @@ -0,0 +1,72 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +#if canImport(Darwin) + import Darwin +#else + import Glibc +#endif + +public protocol _UInt8Type {} +extension UInt8: _UInt8Type {} + +/** casting */ +extension UInt8 { + /** cast because UInt8() because std initializer crash if value is > byte */ + static func with(value: UInt64) -> UInt8 { + let tmp = value & 0xff + return UInt8(tmp) + } + + static func with(value: UInt32) -> UInt8 { + let tmp = value & 0xff + return UInt8(tmp) + } + + static func with(value: UInt16) -> UInt8 { + let tmp = value & 0xff + return UInt8(tmp) + } +} + +/** Bits */ +extension UInt8 { + /** array of bits */ + public func bits() -> [Bit] { + let totalBitsCount = MemoryLayout.size * 8 + + var bitsArray = [Bit](repeating: Bit.zero, count: totalBitsCount) + + for j in 0.. String { + var s = String() + let arr: [Bit] = self.bits() + for idx in arr.indices { + s += (arr[idx] == Bit.one ? "1" : "0") + if idx.advanced(by: 1) % 8 == 0 { s += " " } + } + return s + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Updatable.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Updatable.swift new file mode 100644 index 0000000..8d0b95f --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Updatable.swift @@ -0,0 +1,97 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +/// A type that supports incremental updates. For example Digest or Cipher may be updatable +/// and calculate result incerementally. +public protocol Updatable { + /// Update given bytes in chunks. + /// + /// - parameter bytes: Bytes to process. + /// - parameter isLast: Indicate if given chunk is the last one. No more updates after this call. + /// - returns: Processed partial result data or empty array. + mutating func update(withBytes bytes: ArraySlice, isLast: Bool) throws -> Array + + /// Update given bytes in chunks. + /// + /// - Parameters: + /// - bytes: Bytes to process. + /// - isLast: Indicate if given chunk is the last one. No more updates after this call. + /// - output: Resulting bytes callback. + /// - Returns: Processed partial result data or empty array. + mutating func update(withBytes bytes: ArraySlice, isLast: Bool, output: (_ bytes: Array) -> Void) throws +} + +extension Updatable { + public mutating func update(withBytes bytes: ArraySlice, isLast: Bool = false, output: (_ bytes: Array) -> Void) throws { + let processed = try update(withBytes: bytes, isLast: isLast) + if !processed.isEmpty { + output(processed) + } + } + + public mutating func update(withBytes bytes: ArraySlice, isLast: Bool = false) throws -> Array { + try self.update(withBytes: bytes, isLast: isLast) + } + + public mutating func update(withBytes bytes: Array, isLast: Bool = false) throws -> Array { + try self.update(withBytes: bytes.slice, isLast: isLast) + } + + public mutating func update(withBytes bytes: Array, isLast: Bool = false, output: (_ bytes: Array) -> Void) throws { + try self.update(withBytes: bytes.slice, isLast: isLast, output: output) + } + + /// Finish updates. This may apply padding. + /// - parameter bytes: Bytes to process + /// - returns: Processed data. + public mutating func finish(withBytes bytes: ArraySlice) throws -> Array { + try self.update(withBytes: bytes, isLast: true) + } + + public mutating func finish(withBytes bytes: Array) throws -> Array { + try self.finish(withBytes: bytes.slice) + } + + /// Finish updates. May add padding. + /// + /// - Returns: Processed data + /// - Throws: Error + public mutating func finish() throws -> Array { + try self.update(withBytes: [], isLast: true) + } + + /// Finish updates. This may apply padding. + /// - parameter bytes: Bytes to process + /// - parameter output: Resulting data + /// - returns: Processed data. + public mutating func finish(withBytes bytes: ArraySlice, output: (_ bytes: Array) -> Void) throws { + let processed = try update(withBytes: bytes, isLast: true) + if !processed.isEmpty { + output(processed) + } + } + + public mutating func finish(withBytes bytes: Array, output: (_ bytes: Array) -> Void) throws { + try self.finish(withBytes: bytes.slice, output: output) + } + + /// Finish updates. May add padding. + /// + /// - Parameter output: Processed data + /// - Throws: Error + public mutating func finish(output: (Array) -> Void) throws { + try self.finish(withBytes: [], output: output) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/Utils.swift b/Pods/CryptoSwift/Sources/CryptoSwift/Utils.swift new file mode 100644 index 0000000..b2a658b --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/Utils.swift @@ -0,0 +1,115 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +@_transparent +func rotateLeft(_ value: UInt8, by: UInt8) -> UInt8 { + ((value << by) & 0xff) | (value >> (8 - by)) +} + +@_transparent +func rotateLeft(_ value: UInt16, by: UInt16) -> UInt16 { + ((value << by) & 0xffff) | (value >> (16 - by)) +} + +@_transparent +func rotateLeft(_ value: UInt32, by: UInt32) -> UInt32 { + ((value << by) & 0xffffffff) | (value >> (32 - by)) +} + +@_transparent +func rotateLeft(_ value: UInt64, by: UInt64) -> UInt64 { + (value << by) | (value >> (64 - by)) +} + +@_transparent +func rotateRight(_ value: UInt16, by: UInt16) -> UInt16 { + (value >> by) | (value << (16 - by)) +} + +@_transparent +func rotateRight(_ value: UInt32, by: UInt32) -> UInt32 { + (value >> by) | (value << (32 - by)) +} + +@_transparent +func rotateRight(_ value: UInt64, by: UInt64) -> UInt64 { + ((value >> by) | (value << (64 - by))) +} + +@_transparent +func reversed(_ uint8: UInt8) -> UInt8 { + var v = uint8 + v = (v & 0xf0) >> 4 | (v & 0x0f) << 4 + v = (v & 0xcc) >> 2 | (v & 0x33) << 2 + v = (v & 0xaa) >> 1 | (v & 0x55) << 1 + return v +} + +@_transparent +func reversed(_ uint32: UInt32) -> UInt32 { + var v = uint32 + v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1) + v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2) + v = ((v >> 4) & 0x0f0f0f0f) | ((v & 0x0f0f0f0f) << 4) + v = ((v >> 8) & 0x00ff00ff) | ((v & 0x00ff00ff) << 8) + v = ((v >> 16) & 0xffff) | ((v & 0xffff) << 16) + return v +} + +func xor(_ left: T, _ right: V) -> ArraySlice where T: RandomAccessCollection, V: RandomAccessCollection, T.Element == UInt8, T.Index == Int, V.Element == UInt8, V.Index == Int { + return xor(left, right).slice +} + +func xor(_ left: T, _ right: V) -> Array where T: RandomAccessCollection, V: RandomAccessCollection, T.Element == UInt8, T.Index == Int, V.Element == UInt8, V.Index == Int { + let length = Swift.min(left.count, right.count) + + let buf = UnsafeMutablePointer.allocate(capacity: length) + buf.initialize(repeating: 0, count: length) + defer { + buf.deinitialize(count: length) + buf.deallocate() + } + + // xor + for i in 0.., blockSize: Int, allowance: Int = 0) { + let msgLength = data.count + // Step 1. Append Padding Bits + // append one bit (UInt8 with one bit) to message + data.append(0x80) + + // Step 2. append "0" bit until message length in bits ≡ 448 (mod 512) + let max = blockSize - allowance // 448, 986 + if msgLength % blockSize < max { // 448 + data += Array(repeating: 0, count: max - 1 - (msgLength % blockSize)) + } else { + data += Array(repeating: 0, count: blockSize + max - 1 - (msgLength % blockSize)) + } +} diff --git a/Pods/CryptoSwift/Sources/CryptoSwift/ZeroPadding.swift b/Pods/CryptoSwift/Sources/CryptoSwift/ZeroPadding.swift new file mode 100644 index 0000000..dbe7e36 --- /dev/null +++ b/Pods/CryptoSwift/Sources/CryptoSwift/ZeroPadding.swift @@ -0,0 +1,38 @@ +// +// CryptoSwift +// +// Copyright (C) 2014-2017 Marcin Krzyżanowski +// This software is provided 'as-is', without any express or implied warranty. +// +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: +// +// - The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +// - Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +// - This notice may not be removed or altered from any source or binary distribution. +// + +/// All the bytes that are required to be padded are padded with zero. +/// Zero padding may not be reversible if the original file ends with one or more zero bytes. +struct ZeroPadding: PaddingProtocol { + init() { + } + + func add(to bytes: Array, blockSize: Int) -> Array { + let paddingCount = blockSize - (bytes.count % blockSize) + if paddingCount > 0 { + return bytes + Array(repeating: 0, count: paddingCount) + } + return bytes + } + + func remove(from bytes: Array, blockSize _: Int?) -> Array { + for (idx, value) in bytes.reversed().enumerated() { + if value != 0 { + return Array(bytes[0.. 4.7) + - ObjectMapper (~> 3.4) + - CryptoSwift (1.1.3) + - ObjectMapper (3.5.1) + - SDWebImage (4.4.7): + - SDWebImage/Core (= 4.4.7) + - SDWebImage/Core (4.4.7) + - Toast-Swift (5.0.0) + +DEPENDENCIES: + - Alamofire (~> 4.5) + - AlamofireObjectMapper (~> 5.0) + - CryptoSwift + - SDWebImage (~> 4.0) + - Toast-Swift + +SPEC REPOS: + https://github.com/CocoaPods/Specs.git: + - Alamofire + - AlamofireObjectMapper + - CryptoSwift + - ObjectMapper + - SDWebImage + - Toast-Swift + +SPEC CHECKSUMS: + Alamofire: afc3e7c6db61476cb45cdd23fed06bad03bbc321 + AlamofireObjectMapper: 1989f690e982b71921b9253f53a4f33a9bc00d88 + CryptoSwift: 6b6e488df0598b3e9fa49254ed1a65e8c1b1e10b + ObjectMapper: 70187b8941977c62ccfb423caf6b50be405cabf0 + SDWebImage: c10d14a8883ebd89664f02a422006f66a85c0c5d + Toast-Swift: 36f4720243c8582c2be243a60a51e193c761f541 + +PODFILE CHECKSUM: 0b562daaa596368d56055dd155a6bfc28bc54ce1 + +COCOAPODS: 1.8.4 diff --git a/Pods/ObjectMapper/LICENSE b/Pods/ObjectMapper/LICENSE new file mode 100644 index 0000000..be48bc6 --- /dev/null +++ b/Pods/ObjectMapper/LICENSE @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2014 Hearst + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Pods/ObjectMapper/README-CN.md b/Pods/ObjectMapper/README-CN.md new file mode 100644 index 0000000..1651759 --- /dev/null +++ b/Pods/ObjectMapper/README-CN.md @@ -0,0 +1,500 @@ +# ObjectMapper-CN-Guide +> 文档由Swift老司机活动中心负责翻译,欢迎关注[@SwiftOldDriver](http://weibo.com/6062089411)。翻译有问题可以到 [ObjectMapper-CN-Guide](https://github.com/SwiftOldDriver/ObjectMapper-CN-Guide) 提 PR。 + +[ObjectMapper](https://github.com/Hearst-DD/ObjectMapper) 是一个使用 Swift 编写的用于 model 对象(类和结构体)和 JSON 之间转换的框架。 + +- [特性](#特性) +- [基础使用方法](#基础使用方法) +- [映射嵌套对象](#映射嵌套对象) +- [自定义转换规则](#自定义转换规则) +- [继承](#继承) +- [泛型对象](#泛型对象) +- [映射时的上下文对象](#映射时的上下文对象) +- [ObjectMapper + Alamofire](#objectmapper--alamofire) +- [ObjectMapper + Realm](#objectmapper--realm) +- [待完成](#待完成) +- [安装](#安装) + +# 特性: +- 把 JSON 映射成对象 +- 把对象映射 JSON +- 支持嵌套对象 (单独的成员变量、在数组或字典中都可以) +- 在转换过程支持自定义规则 +- 支持结构体( Struct ) +- [Immutable support](#immutablemappable-protocol-beta) (目前还在 beta ) + +# 基础使用方法 +为了支持映射,类或者结构体只需要实现```Mappable```协议。这个协议包含以下方法: +```swift +init?(map: Map) +mutating func mapping(map: Map) +``` +ObjectMapper使用自定义的```<-``` 运算符来声明成员变量和 JSON 的映射关系。 +```swift +class User: Mappable { + var username: String? + var age: Int? + var weight: Double! + var array: [AnyObject]? + var dictionary: [String : AnyObject] = [:] + var bestFriend: User? // 嵌套的 User 对象 + var friends: [User]? // Users 的数组 + var birthday: NSDate? + + required init?(map: Map) { + + } + + // Mappable + func mapping(map: Map) { + username <- map["username"] + age <- map["age"] + weight <- map["weight"] + array <- map["arr"] + dictionary <- map["dict"] + bestFriend <- map["best_friend"] + friends <- map["friends"] + birthday <- (map["birthday"], DateTransform()) + } +} + +struct Temperature: Mappable { + var celsius: Double? + var fahrenheit: Double? + + init?(map: Map) { + + } + + mutating func mapping(map: Map) { + celsius <- map["celsius"] + fahrenheit <- map["fahrenheit"] + } +} +``` + +一旦你的对象实现了 `Mappable`, ObjectMapper就可以让你轻松的实现和 JSON 之间的转换。 + +把 JSON 字符串转成 model 对象: + +```swift +let user = User(JSONString: JSONString) +``` + +把一个 model 转成 JSON 字符串: + +```swift +let JSONString = user.toJSONString(prettyPrint: true) +``` + +也可以使用`Mapper.swift`类来完成转换(这个类还额外提供了一些函数来处理一些特殊的情况: + +```swift +// 把 JSON 字符串转成 Model +let user = Mapper().map(JSONString: JSONString) +// 根据 Model 生成 JSON 字符串 +let JSONString = Mapper().toJSONString(user, prettyPrint: true) +``` + +ObjectMapper支持以下的类型映射到对象中: + +- `Int` +- `Bool` +- `Double` +- `Float` +- `String` +- `RawRepresentable` (枚举) +- `Array` +- `Dictionary` +- `Object` +- `Array` +- `Array>` +- `Set` +- `Dictionary` +- `Dictionary>` +- 以上所有的 Optional 类型 +- 以上所有的隐式强制解包类型(Implicitly Unwrapped Optional) + +## `Mappable` 协议 + +#### `mutating func mapping(map: Map)` +所有的映射最后都会调用到这个函数。当解析 JSON 时,这个函数会在对象创建成功后被执行。当生成 JSON 时就只有这个函数会被对象调用。 + +#### `init?(map: Map)` +这个可失败的初始化函数是 ObjectMapper 创建对象的时候使用的。开发者可以通过这个函数在映射前校验 JSON 。如果在这个方法里返回 nil 就不会执行 `mapping` 函数。可以通过传入的保存着 JSON 的 `Map` 对象进行校验: + +```swift +required init?(map: Map){ + // 检查 JSON 里是否有一定要有的 "name" 属性 + if map.JSONDictionary["name"] == nil { + return nil + } +} +``` + +## `StaticMappable` 协议 +`StaticMappable` 是 `Mappable` 之外的另一种选择。 这个协议可以让开发者通过一个静态函数初始化对象而不是通过 `init?(map: Map)`。 + +注意: `StaticMappable` 和 `Mappable` 都继承了 `BaseMappable` 协议。 `BaseMappable` 协议声明了 `mapping(map: Map)` 函数。 + +#### `static func objectForMapping(map: Map) -> BaseMappable?` +ObjectMapper 使用这个函数获取对象后进行映射。开发者需要在这个函数里返回一个实现 `BaseMappable` 对象的实例。这个函数也可以用于: + +- 在对象进行映射前校验 JSON +- 提供一个缓存过的对象用于映射 +- 返回另外一种类型的对象(当然是必须实现了 BaseMappable)用于映射。比如你可能通过检查 JSON 推断出用于映射的对象 ([看这个例子](https://github.com/Hearst-DD/ObjectMapper/blob/master/ObjectMapperTests/ClassClusterTests.swift#L62))。 + +如果你需要在 extension 里实现 ObjectMapper,你需要选择这个协议而不是 `Mappable` 。 + +## `ImmutableMappable` Protocol + +使用 `ImmutableMappable` 可以映射不可变的属性。下面的表格展示了 `ImmutableMappable` 和 `Mappable` 的不同: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ImmutableMappableMappable
Properties
+
+let id: Int
+let name: String?
+
+
+
+var id: Int!
+var name: String?
+
+
JSON -> Model
+
+init(map: Map) throws {
+  id   = try map.value("id")
+  name = try? map.value("name")
+}
+
+
+
+mutating func mapping(map: Map) {
+  id   <- map["id"]
+  name <- map["name"]
+}
+
+
Model -> JSON
+
+mutating func mapping(map: Map) {
+  id   >>> map["id"]
+  name >>> map["name"]
+}
+
+
+
+mutating func mapping(map: Map) {
+  id   <- map["id"]
+  name <- map["name"]
+}
+
+
Initializing
+
+try User(JSONString: JSONString)
+
+
+
+User(JSONString: JSONString)
+
+
+ +#### `init(map: Map) throws` + +这个可能抛出异常的初始化函数用于在提供的 `Map` 里映射不可变属性。每个不可变的初始化属性都要在这个初始化函数里初始化。 + +当发生下列情况时初始化函数会抛出一个错误: + +- `Map` 根据提供的键名获取不到对应值 +- `Map` 使用 `Transform` 后没有得到值 + +`ImmutableMappable` 使用 `Map.value(_:using:)` 方法从 `Map` 中获取值。因为可能抛出异常,这个方法在使用时需要使用 `try` 关键字。 `Optional` 的属性可以简单的用 `try?` 处理。 + +```swift +init(map: Map) throws { + name = try map.value("name") // throws an error when it fails + createdAt = try map.value("createdAt", using: DateTransform()) // throws an error when it fails + updatedAt = try? map.value("updatedAt", using: DateTransform()) // optional + posts = (try? map.value("posts")) ?? [] // optional + default value +} +``` + +#### `mutating func mapping(map: Map)` + +这个方法是在 Model 转回 JSON 时调用的。因为不可变的属性不能被 `<-` 映射,所以映射回来时需要使用 `>>>` 。 + +```swift +mutating func mapping(map: Map) { + name >>> map["name"] + createdAt >>> (map["createdAt"], DateTransform()) + updatedAt >>> (map["updatedAt"], DateTransform()) + posts >>> map["posts"] +} +``` +# 轻松映射嵌套对象 + +ObjectMapper 支持使用点语法来轻松实现嵌套对象的映射。比如有如下的 JSON 字符串: + +```json +"distance" : { + "text" : "102 ft", + "value" : 31 +} +``` +你可以通过这种写法直接访问到嵌套对象: + +```swift +func mapping(map: Map) { + distance <- map["distance.value"] +} +``` +嵌套的键名也支持访问数组中的值。如果有一个返回的 JSON 是一个包含 distance 的数组,可以通过这种写法访问: + +``` +distance <- map["distances.0.value"] +``` +如果你的键名刚好含有 `.` 符号,你需要特别声明关闭上面提到的获取嵌套对象功能: + +```swift +func mapping(map: Map) { + identifier <- map["app.identifier", nested: false] +} +``` +如果刚好有嵌套的对象的键名还有 `.` ,可以在中间加入一个自定义的分割符([#629](https://github.com/Hearst-DD/ObjectMapper/pull/629)): +```swift +func mapping(map: Map) { + appName <- map["com.myapp.info->com.myapp.name", delimiter: "->"] +} +``` +这种情况的 JSON 是这样的: + +```json +"com.myapp.info" : { + "com.myapp.name" : "SwiftOldDriver" +} +``` + +# 自定义转换规则 +ObjectMapper 也支持在映射时自定义转换规则。如果要使用自定义转换,创建一个 tuple(元祖)包含 ```map["field_name"]``` 和你要使用的变换放在 ```<-``` 的右边: + +```swift +birthday <- (map["birthday"], DateTransform()) +``` +当解析 JSON 时上面的转换会把 JSON 里面的 Int 值转成一个 NSDate ,如果是对象转为 JSON 时,则会把 NSDate 对象转成 Int 值。 + +只要实现```TransformType``` 协议就可以轻松的创建自定义的转换规则: + +```swift +public protocol TransformType { + associatedtype Object + associatedtype JSON + + func transformFromJSON(_ value: Any?) -> Object? + func transformToJSON(_ value: Object?) -> JSON? +} +``` + +### TransformOf +大多数情况下你都可以使用框架提供的转换类 ```TransformOf``` 来快速的实现一个期望的转换。 ```TransformOf``` 的初始化需要两个类型和两个闭包。两个类型声明了转换的目标类型和源类型,闭包则实现具体转换逻辑。 + +举个例子,如果你想要把一个 JSON 字符串转成 Int ,你可以像这样使用 ```TransformOf``` : + +```swift +let transform = TransformOf(fromJSON: { (value: String?) -> Int? in + // 把值从 String? 转成 Int? + return Int(value!) +}, toJSON: { (value: Int?) -> String? in + // 把值从 Int? 转成 String? + if let value = value { + return String(value) + } + return nil +}) + +id <- (map["id"], transform) +``` +这是一种更省略的写法: + +```swift +id <- (map["id"], TransformOf(fromJSON: { Int($0!) }, toJSON: { $0.map { String($0) } })) +``` +# 继承 + +实现了 ```Mappable``` 协议的类可以容易的被继承。当继承一个 mappable 的类时,使用这样的结构: + +```swift +class Base: Mappable { + var base: String? + + required init?(map: Map) { + + } + + func mapping(map: Map) { + base <- map["base"] + } +} + +class Subclass: Base { + var sub: String? + + required init?(map: Map) { + super.init(map) + } + + override func mapping(map: Map) { + super.mapping(map) + + sub <- map["sub"] + } +} +``` + +注意确认子类中的实现调用了父类中正确的初始化器和映射函数。 + +# 泛型对象 + +ObjectMapper 可以处理泛型只要这个泛型也实现了`Mappable`协议。看这个例子: + +```swift +class Result: Mappable { + var result: T? + + required init?(map: Map){ + + } + + func mapping(map: Map) { + result <- map["result"] + } +} + +let result = Mapper>().map(JSON) +``` +# 映射时的上下文对象 + +`Map` 是在映射时传入的对象,带有一个 optional `MapContext` 对象,开发者可以通过使用这个对象在映射时传入一些信息。 + +为了使用这个特性,需要先创建一个对象实现了 `MapContext` 协议(这个协议是空的),然后在初始化时传入 `Mapper` 中。 + +```swift +struct Context: MapContext { + var importantMappingInfo = "映射时需要知道的额外信息" +} + +class User: Mappable { + var name: String? + + required init?(map: Map){ + + } + + func mapping(map: Map){ + if let context = map.context as? Context { + // 获取到额外的信息 + } + } +} + +let context = Context() +let user = Mapper(context: context).map(JSONString) +``` + +# ObjectMapper + Alamofire + +如果网络层你使用的是 [Alamofire](https://github.com/Alamofire/Alamofire) ,并且你希望把返回的结果转换成 Swift 对象,你可以使用 [AlamofireObjectMapper](https://github.com/tristanhimmelman/AlamofireObjectMapper) 。这是一个使用 ObjectMapper 实现的把返回的 JSON 自动转成 Swift 对象的 Alamofire 的扩展。 + + +# ObjectMapper + Realm + +ObjectMapper 可以和 Realm 一起配合使用。使用下面的声明结构就可以使用 ObjectMapper 生成 Realm 对象: + +```swift +class Model: Object, Mappable { + dynamic var name = "" + + required convenience init?(map: Map) { + self.init() + } + + func mapping(map: Map) { + name <- map["name"] + } +} +``` + +如果你想要序列化相关联的 RealmObject,你可以使用 [ObjectMapper+Realm](https://github.com/jakenberg/ObjectMapper-Realm)。这是一个简单的 Realm 扩展,用于把任意的 JSON 序列化成 Realm 的类(ealm's List class。) + +注意:使用 ObjectMappers 的 `toJSON` 函数来生成 JSON 字符串只在 Realm 的写事务中有效(write transaction)。这是因为 ObjectMapper 在解析和生成时在映射函数( `<-` )中使用 `inout` 作为标记( flag )。Realm 会检测到标记并且强制要求 `toJSON` 函数只能在一个写的事务中调用,即使这个对象并没有被修改。 + +# 待完成 +- 改善错误的处理。可能使用 `throws` 来处理。 +- 相关类的文档完善 + +# 安装 +### Cocoapods +如果你的项目使用 [CocoaPods 0.36 及以上](http://blog.cocoapods.org/Pod-Authors-Guide-to-CocoaPods-Frameworks/) 的版本,你可以把下面内容添加到在 `Podfile` 中,将 ObjectMapper 添加到你的项目中: + +```ruby +pod 'ObjectMapper', '~> 2.2' +``` + +### Carthage +如果你的项目使用 [Carthage](https://github.com/Carthage/Carthage) ,你可以把下面的内容添加到 `Cartfile` 中,将 ObjectMapper 的依赖到你的项目中: + +``` +github "Hearst-DD/ObjectMapper" ~> 2.2 +``` + +### Swift Package Manager +如果你的项目使用 [Swift Package Manager](https://swift.org/package-manager/) ,那么你可以把下面内容添加到 `Package.swift` 中的 `dependencies` 数组中,将 ObjectMapper 的依赖到你的项目中: + +```swift +.Package(url: "https://github.com/Hearst-DD/ObjectMapper.git", majorVersion: 2, minor: 2), +``` + + +### Submodule +此外,ObjectMapper 也可以作为一个 submodule 添加到项目中: + +1. 打开终端,使用 `cd` 命令进入项目文件的根目录下,然后在终端中输入 `git submodule add https://github.com/Hearst-DD/ObjectMapper.git` ,把 ObjectMapper 作为项目的一个 [submodule](http://git-scm.com/docs/git-submodule) 添加进来。 +2. 打开 `ObjectMapper` 文件,并将 `ObjectMapper.xcodeproj` 拖进你 app 项目的文件导航中。 +3. 在 Xcode 中,文件导航中点击蓝色项目图标进入到 target 配置界面,在侧边栏的 "TARGETS" 下选择主工程对应的target。 +4. 确保 `ObjectMapper.framework` 的部署版本( deployment target )和主工程的部署版本保持一致。 +5. 在配置界面的顶部选项栏中,打开 "Build Phases" 面板。 +6. 展开 "Target Dependencies" 组,并添加 `ObjectMapper.framework` 。 +7. 点击面板左上角的 `+` 按钮,选择 "New Copy Files Phase"。将这个阶段重命名为 "Copy Frameworks",设置 "Destination" 为 "Frameworks",最后添加 `ObjectMapper.framework` 。 + + diff --git a/Pods/ObjectMapper/Sources/CodableTransform.swift b/Pods/ObjectMapper/Sources/CodableTransform.swift new file mode 100644 index 0000000..4cb72d5 --- /dev/null +++ b/Pods/ObjectMapper/Sources/CodableTransform.swift @@ -0,0 +1,73 @@ +// +// CodableTransform.swift +// ObjectMapper +// +// Created by Jari Kalinainen on 10/10/2018. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// Transforms JSON dictionary to Codable type T and back +open class CodableTransform: TransformType { + + public typealias Object = T + public typealias JSON = Any + + public init() {} + + open func transformFromJSON(_ value: Any?) -> Object? { + var _data: Data? = nil + switch value { + case let dict as [String : Any]: + _data = try? JSONSerialization.data(withJSONObject: dict, options: []) + case let array as [[String : Any]]: + _data = try? JSONSerialization.data(withJSONObject: array, options: []) + default: + _data = nil + } + guard let data = _data else { return nil } + + do { + let decoder = JSONDecoder() + let item = try decoder.decode(T.self, from: data) + return item + } catch { + return nil + } + } + + open func transformToJSON(_ value: T?) -> JSON? { + guard let item = value else { + return nil + } + do { + let encoder = JSONEncoder() + let data = try encoder.encode(item) + let dictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) + return dictionary + } catch { + return nil + } + } +} diff --git a/Pods/ObjectMapper/Sources/CustomDateFormatTransform.swift b/Pods/ObjectMapper/Sources/CustomDateFormatTransform.swift new file mode 100644 index 0000000..f7b8c54 --- /dev/null +++ b/Pods/ObjectMapper/Sources/CustomDateFormatTransform.swift @@ -0,0 +1,40 @@ +// +// CustomDateFormatTransform.swift +// ObjectMapper +// +// Created by Dan McCracken on 3/8/15. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class CustomDateFormatTransform: DateFormatterTransform { + + public init(formatString: String) { + let formatter = DateFormatter() + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.dateFormat = formatString + + super.init(dateFormatter: formatter) + } +} diff --git a/Pods/ObjectMapper/Sources/DataTransform.swift b/Pods/ObjectMapper/Sources/DataTransform.swift new file mode 100644 index 0000000..87cb25c --- /dev/null +++ b/Pods/ObjectMapper/Sources/DataTransform.swift @@ -0,0 +1,50 @@ +// +// DataTransform.swift +// ObjectMapper +// +// Created by Yagrushkin, Evgeny on 8/30/16. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class DataTransform: TransformType { + public typealias Object = Data + public typealias JSON = String + + public init() {} + + open func transformFromJSON(_ value: Any?) -> Data? { + guard let string = value as? String else{ + return nil + } + return Data(base64Encoded: string) + } + + open func transformToJSON(_ value: Data?) -> String? { + guard let data = value else{ + return nil + } + return data.base64EncodedString() + } +} diff --git a/Pods/ObjectMapper/Sources/DateFormatterTransform.swift b/Pods/ObjectMapper/Sources/DateFormatterTransform.swift new file mode 100644 index 0000000..9828e2d --- /dev/null +++ b/Pods/ObjectMapper/Sources/DateFormatterTransform.swift @@ -0,0 +1,54 @@ +// +// DateFormatterTransform.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2015-03-09. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class DateFormatterTransform: TransformType { + public typealias Object = Date + public typealias JSON = String + + public let dateFormatter: DateFormatter + + public init(dateFormatter: DateFormatter) { + self.dateFormatter = dateFormatter + } + + open func transformFromJSON(_ value: Any?) -> Date? { + if let dateString = value as? String { + return dateFormatter.date(from: dateString) + } + return nil + } + + open func transformToJSON(_ value: Date?) -> String? { + if let date = value { + return dateFormatter.string(from: date) + } + return nil + } +} diff --git a/Pods/ObjectMapper/Sources/DateTransform.swift b/Pods/ObjectMapper/Sources/DateTransform.swift new file mode 100644 index 0000000..f55c87f --- /dev/null +++ b/Pods/ObjectMapper/Sources/DateTransform.swift @@ -0,0 +1,75 @@ +// +// DateTransform.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-13. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class DateTransform: TransformType { + public typealias Object = Date + public typealias JSON = Double + + public enum Unit: TimeInterval { + case seconds = 1 + case milliseconds = 1_000 + + func addScale(to interval: TimeInterval) -> TimeInterval { + return interval * rawValue + } + + func removeScale(from interval: TimeInterval) -> TimeInterval { + return interval / rawValue + } + } + + private let unit: Unit + + public init(unit: Unit = .seconds) { + self.unit = unit + } + + open func transformFromJSON(_ value: Any?) -> Date? { + var timeInterval: TimeInterval? + if let timeInt = value as? Double { + timeInterval = TimeInterval(timeInt) + } + + if let timeStr = value as? String { + timeInterval = TimeInterval(atof(timeStr)) + } + + return timeInterval.flatMap { + return Date(timeIntervalSince1970: unit.removeScale(from: $0)) + } + } + + open func transformToJSON(_ value: Date?) -> Double? { + if let date = value { + return Double(unit.addScale(to: date.timeIntervalSince1970)) + } + return nil + } +} diff --git a/Pods/ObjectMapper/Sources/DictionaryTransform.swift b/Pods/ObjectMapper/Sources/DictionaryTransform.swift new file mode 100644 index 0000000..35a1e6f --- /dev/null +++ b/Pods/ObjectMapper/Sources/DictionaryTransform.swift @@ -0,0 +1,76 @@ +// +// DictionaryTransform.swift +// ObjectMapper +// +// Created by Milen Halachev on 7/20/16. +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +///Transforms [String: AnyObject] <-> [Key: Value] where Key is RawRepresentable as String, Value is Mappable +public struct DictionaryTransform: TransformType where Key: Hashable, Key: RawRepresentable, Key.RawValue == String, Value: Mappable { + + public init() { + + } + + public func transformFromJSON(_ value: Any?) -> [Key: Value]? { + + guard let json = value as? [String: Any] else { + + return nil + } + + let result = json.reduce([:]) { (result, element) -> [Key: Value] in + + guard + let key = Key(rawValue: element.0), + let valueJSON = element.1 as? [String: Any], + let value = Value(JSON: valueJSON) + else { + + return result + } + + var result = result + result[key] = value + return result + } + + return result + } + + public func transformToJSON(_ value: [Key: Value]?) -> Any? { + + let result = value?.reduce([:]) { (result, element) -> [String: Any] in + + let key = element.0.rawValue + let value = element.1.toJSON() + + var result = result + result[key] = value + return result + } + + return result + } +} diff --git a/Pods/ObjectMapper/Sources/EnumOperators.swift b/Pods/ObjectMapper/Sources/EnumOperators.swift new file mode 100644 index 0000000..3693a1d --- /dev/null +++ b/Pods/ObjectMapper/Sources/EnumOperators.swift @@ -0,0 +1,120 @@ +// +// EnumOperators.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2016-09-26. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + + +// MARK:- Raw Representable types + +/// Object of Raw Representable type +public func <- (left: inout T, right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: T, right: Map) { + left >>> (right, EnumTransform()) +} + + +/// Optional Object of Raw Representable type +public func <- (left: inout T?, right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: T?, right: Map) { + left >>> (right, EnumTransform()) +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly Unwrapped Optional Object of Raw Representable type +public func <- (left: inout T!, right: Map) { + left <- (right, EnumTransform()) +} +#endif + +// MARK:- Arrays of Raw Representable type + +/// Array of Raw Representable object +public func <- (left: inout [T], right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: [T], right: Map) { + left >>> (right, EnumTransform()) +} + + +/// Array of Raw Representable object +public func <- (left: inout [T]?, right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: [T]?, right: Map) { + left >>> (right, EnumTransform()) +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Array of Raw Representable object +public func <- (left: inout [T]!, right: Map) { + left <- (right, EnumTransform()) +} +#endif + +// MARK:- Dictionaries of Raw Representable type + +/// Dictionary of Raw Representable object +public func <- (left: inout [String: T], right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: [String: T], right: Map) { + left >>> (right, EnumTransform()) +} + + +/// Dictionary of Raw Representable object +public func <- (left: inout [String: T]?, right: Map) { + left <- (right, EnumTransform()) +} + +public func >>> (left: [String: T]?, right: Map) { + left >>> (right, EnumTransform()) +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Dictionary of Raw Representable object +public func <- (left: inout [String: T]!, right: Map) { + left <- (right, EnumTransform()) +} +#endif diff --git a/Pods/ObjectMapper/Sources/EnumTransform.swift b/Pods/ObjectMapper/Sources/EnumTransform.swift new file mode 100644 index 0000000..f63d3ad --- /dev/null +++ b/Pods/ObjectMapper/Sources/EnumTransform.swift @@ -0,0 +1,50 @@ +// +// EnumTransform.swift +// ObjectMapper +// +// Created by Kaan Dedeoglu on 3/20/15. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class EnumTransform: TransformType { + public typealias Object = T + public typealias JSON = T.RawValue + + public init() {} + + open func transformFromJSON(_ value: Any?) -> T? { + if let raw = value as? T.RawValue { + return T(rawValue: raw) + } + return nil + } + + open func transformToJSON(_ value: T?) -> T.RawValue? { + if let obj = value { + return obj.rawValue + } + return nil + } +} diff --git a/Pods/ObjectMapper/Sources/FromJSON.swift b/Pods/ObjectMapper/Sources/FromJSON.swift new file mode 100755 index 0000000..78268de --- /dev/null +++ b/Pods/ObjectMapper/Sources/FromJSON.swift @@ -0,0 +1,202 @@ +// +// FromJSON.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-09. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2016 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +internal final class FromJSON { + + /// Basic type + class func basicType(_ field: inout FieldType, object: FieldType?) { + if let value = object { + field = value + } + } + + /// optional basic type + class func optionalBasicType(_ field: inout FieldType?, object: FieldType?) { + field = object + } + + // Code targeting the Swift 4.1 compiler and below. + #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) + /// Implicitly unwrapped optional basic type + class func optionalBasicType(_ field: inout FieldType!, object: FieldType?) { + field = object + } + #endif + + /// Mappable object + class func object(_ field: inout N, map: Map) { + if map.toObject { + field = Mapper(context: map.context).map(JSONObject: map.currentValue, toObject: field) + } else if let value: N = Mapper(context: map.context).map(JSONObject: map.currentValue) { + field = value + } + } + + /// Optional Mappable Object + + class func optionalObject(_ field: inout N?, map: Map) { + if let f = field , map.toObject && map.currentValue != nil { + field = Mapper(context: map.context).map(JSONObject: map.currentValue, toObject: f) + } else { + field = Mapper(context: map.context).map(JSONObject: map.currentValue) + } + } + + // Code targeting the Swift 4.1 compiler and below. + #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) + /// Implicitly unwrapped Optional Mappable Object + class func optionalObject(_ field: inout N!, map: Map) { + if let f = field , map.toObject && map.currentValue != nil { + field = Mapper(context: map.context).map(JSONObject: map.currentValue, toObject: f) + } else { + field = Mapper(context: map.context).map(JSONObject: map.currentValue) + } + } + #endif + + /// mappable object array + class func objectArray(_ field: inout Array, map: Map) { + if let objects = Mapper(context: map.context).mapArray(JSONObject: map.currentValue) { + field = objects + } + } + + /// optional mappable object array + + class func optionalObjectArray(_ field: inout Array?, map: Map) { + if let objects: Array = Mapper(context: map.context).mapArray(JSONObject: map.currentValue) { + field = objects + } else { + field = nil + } + } + + // Code targeting the Swift 4.1 compiler and below. + #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) + /// Implicitly unwrapped optional mappable object array + class func optionalObjectArray(_ field: inout Array!, map: Map) { + if let objects: Array = Mapper(context: map.context).mapArray(JSONObject: map.currentValue) { + field = objects + } else { + field = nil + } + } + #endif + + /// mappable object array + class func twoDimensionalObjectArray(_ field: inout Array>, map: Map) { + if let objects = Mapper(context: map.context).mapArrayOfArrays(JSONObject: map.currentValue) { + field = objects + } + } + + /// optional mappable 2 dimentional object array + class func optionalTwoDimensionalObjectArray(_ field: inout Array>?, map: Map) { + field = Mapper(context: map.context).mapArrayOfArrays(JSONObject: map.currentValue) + } + + // Code targeting the Swift 4.1 compiler and below. + #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) + /// Implicitly unwrapped optional 2 dimentional mappable object array + class func optionalTwoDimensionalObjectArray(_ field: inout Array>!, map: Map) { + field = Mapper(context: map.context).mapArrayOfArrays(JSONObject: map.currentValue) + } + #endif + + /// Dctionary containing Mappable objects + class func objectDictionary(_ field: inout Dictionary, map: Map) { + if map.toObject { + field = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue, toDictionary: field) + } else { + if let objects = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue) { + field = objects + } + } + } + + /// Optional dictionary containing Mappable objects + class func optionalObjectDictionary(_ field: inout Dictionary?, map: Map) { + if let f = field , map.toObject && map.currentValue != nil { + field = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue, toDictionary: f) + } else { + field = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue) + } + } + + // Code targeting the Swift 4.1 compiler and below. + #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) + /// Implicitly unwrapped Dictionary containing Mappable objects + class func optionalObjectDictionary(_ field: inout Dictionary!, map: Map) { + if let f = field , map.toObject && map.currentValue != nil { + field = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue, toDictionary: f) + } else { + field = Mapper(context: map.context).mapDictionary(JSONObject: map.currentValue) + } + } + #endif + + /// Dictionary containing Array of Mappable objects + class func objectDictionaryOfArrays(_ field: inout Dictionary, map: Map) { + if let objects = Mapper(context: map.context).mapDictionaryOfArrays(JSONObject: map.currentValue) { + field = objects + } + } + + /// Optional Dictionary containing Array of Mappable objects + class func optionalObjectDictionaryOfArrays(_ field: inout Dictionary?, map: Map) { + field = Mapper(context: map.context).mapDictionaryOfArrays(JSONObject: map.currentValue) + } + + // Code targeting the Swift 4.1 compiler and below. + #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) + /// Implicitly unwrapped Dictionary containing Array of Mappable objects + class func optionalObjectDictionaryOfArrays(_ field: inout Dictionary!, map: Map) { + field = Mapper(context: map.context).mapDictionaryOfArrays(JSONObject: map.currentValue) + } + #endif + + /// mappable object Set + class func objectSet(_ field: inout Set, map: Map) { + if let objects = Mapper(context: map.context).mapSet(JSONObject: map.currentValue) { + field = objects + } + } + + /// optional mappable object array + class func optionalObjectSet(_ field: inout Set?, map: Map) { + field = Mapper(context: map.context).mapSet(JSONObject: map.currentValue) + } + + // Code targeting the Swift 4.1 compiler and below. + #if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) + /// Implicitly unwrapped optional mappable object array + class func optionalObjectSet(_ field: inout Set!, map: Map) { + field = Mapper(context: map.context).mapSet(JSONObject: map.currentValue) + } + #endif +} diff --git a/Pods/ObjectMapper/Sources/HexColorTransform.swift b/Pods/ObjectMapper/Sources/HexColorTransform.swift new file mode 100644 index 0000000..1f02289 --- /dev/null +++ b/Pods/ObjectMapper/Sources/HexColorTransform.swift @@ -0,0 +1,144 @@ +// +// HexColorTransform.swift +// ObjectMapper +// +// Created by Vitaliy Kuzmenko on 10/10/16. +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#if os(iOS) || os(tvOS) || os(watchOS) +import UIKit +#elseif os(macOS) +import Cocoa +#endif + +#if os(iOS) || os(tvOS) || os(watchOS) || os(macOS) +open class HexColorTransform: TransformType { + + #if os(iOS) || os(tvOS) || os(watchOS) + public typealias Object = UIColor + #else + public typealias Object = NSColor + #endif + + public typealias JSON = String + + var prefix: Bool = false + + var alpha: Bool = false + + public init(prefixToJSON: Bool = false, alphaToJSON: Bool = false) { + alpha = alphaToJSON + prefix = prefixToJSON + } + + open func transformFromJSON(_ value: Any?) -> Object? { + if let rgba = value as? String { + if rgba.hasPrefix("#") { + let index = rgba.index(rgba.startIndex, offsetBy: 1) + let hex = String(rgba[index...]) + return getColor(hex: hex) + } else { + return getColor(hex: rgba) + } + } + return nil + } + + open func transformToJSON(_ value: Object?) -> JSON? { + if let value = value { + return hexString(color: value) + } + return nil + } + + fileprivate func hexString(color: Object) -> String { + let comps = color.cgColor.components! + let compsCount = color.cgColor.numberOfComponents + let r: Int + let g: Int + var b: Int + let a = Int(comps[compsCount - 1] * 255) + if compsCount == 4 { // RGBA + r = Int(comps[0] * 255) + g = Int(comps[1] * 255) + b = Int(comps[2] * 255) + } else { // Grayscale + r = Int(comps[0] * 255) + g = Int(comps[0] * 255) + b = Int(comps[0] * 255) + } + var hexString: String = "" + if prefix { + hexString = "#" + } + hexString += String(format: "%02X%02X%02X", r, g, b) + + if alpha { + hexString += String(format: "%02X", a) + } + return hexString + } + + fileprivate func getColor(hex: String) -> Object? { + var red: CGFloat = 0.0 + var green: CGFloat = 0.0 + var blue: CGFloat = 0.0 + var alpha: CGFloat = 1.0 + + let scanner = Scanner(string: hex) + var hexValue: CUnsignedLongLong = 0 + if scanner.scanHexInt64(&hexValue) { + switch (hex.count) { + case 3: + red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 + green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 + blue = CGFloat(hexValue & 0x00F) / 15.0 + case 4: + red = CGFloat((hexValue & 0xF000) >> 12) / 15.0 + green = CGFloat((hexValue & 0x0F00) >> 8) / 15.0 + blue = CGFloat((hexValue & 0x00F0) >> 4) / 15.0 + alpha = CGFloat(hexValue & 0x000F) / 15.0 + case 6: + red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 + green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 + blue = CGFloat(hexValue & 0x0000FF) / 255.0 + case 8: + red = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0 + green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0 + blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0 + alpha = CGFloat(hexValue & 0x000000FF) / 255.0 + default: + // Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8 + return nil + } + } else { + // "Scan hex error + return nil + } + #if os(iOS) || os(tvOS) || os(watchOS) + return UIColor(red: red, green: green, blue: blue, alpha: alpha) + #else + return NSColor(red: red, green: green, blue: blue, alpha: alpha) + #endif + } +} +#endif diff --git a/Pods/ObjectMapper/Sources/ISO8601DateTransform.swift b/Pods/ObjectMapper/Sources/ISO8601DateTransform.swift new file mode 100644 index 0000000..1f256ea --- /dev/null +++ b/Pods/ObjectMapper/Sources/ISO8601DateTransform.swift @@ -0,0 +1,47 @@ +// +// ISO8601DateTransform.swift +// ObjectMapper +// +// Created by Jean-Pierre Mouilleseaux on 21 Nov 2014. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +public extension DateFormatter { + convenience init(withFormat format : String, locale : String) { + self.init() + self.locale = Locale(identifier: locale) + dateFormat = format + } +} + +open class ISO8601DateTransform: DateFormatterTransform { + + static let reusableISODateFormatter = DateFormatter(withFormat: "yyyy-MM-dd'T'HH:mm:ssZZZZZ", locale: "en_US_POSIX") + + public init() { + super.init(dateFormatter: ISO8601DateTransform.reusableISODateFormatter) + } +} + diff --git a/Pods/ObjectMapper/Sources/ImmutableMappable.swift b/Pods/ObjectMapper/Sources/ImmutableMappable.swift new file mode 100644 index 0000000..1f67824 --- /dev/null +++ b/Pods/ObjectMapper/Sources/ImmutableMappable.swift @@ -0,0 +1,376 @@ +// +// ImmutableMappble.swift +// ObjectMapper +// +// Created by Suyeol Jeon on 23/09/2016. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +public protocol ImmutableMappable: BaseMappable { + init(map: Map) throws +} + +public extension ImmutableMappable { + + /// Implement this method to support object -> JSON transform. + func mapping(map: Map) {} + + /// Initializes object from a JSON String + init(JSONString: String, context: MapContext? = nil) throws { + self = try Mapper(context: context).map(JSONString: JSONString) + } + + /// Initializes object from a JSON Dictionary + init(JSON: [String: Any], context: MapContext? = nil) throws { + self = try Mapper(context: context).map(JSON: JSON) + } + + /// Initializes object from a JSONObject + init(JSONObject: Any, context: MapContext? = nil) throws { + self = try Mapper(context: context).map(JSONObject: JSONObject) + } + +} + +public extension Map { + + fileprivate func currentValue(for key: String, nested: Bool? = nil, delimiter: String = ".") -> Any? { + let isNested = nested ?? key.contains(delimiter) + return self[key, nested: isNested, delimiter: delimiter].currentValue + } + + // MARK: Basic + + /// Returns a value or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> T { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let value = currentValue as? T else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '\(T.self)'", file: file, function: function, line: line) + } + return value + } + + /// Returns a transformed value or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", using transform: Transform, file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> Transform.Object { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let value = transform.transformFromJSON(currentValue) else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot transform to '\(Transform.Object.self)' using \(transform)", file: file, function: function, line: line) + } + return value + } + + /// Returns a RawRepresentable type or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> T { + return try self.value(key, nested: nested, delimiter: delimiter, using: EnumTransform(), file: file, function: function, line: line) + } + + /// Returns a RawRepresentable type or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> T? { + return try self.value(key, nested: nested, delimiter: delimiter, using: EnumTransform(), file: file, function: function, line: line) + } + + /// Returns a `[RawRepresentable]` type or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [T] { + return try self.value(key, nested: nested, delimiter: delimiter, using: EnumTransform(), file: file, function: function, line: line) + } + + /// Returns a `[RawRepresentable]` type or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [T]? { + return try self.value(key, nested: nested, delimiter: delimiter, using: EnumTransform(), file: file, function: function, line: line) + } + + // MARK: BaseMappable + + /// Returns a `BaseMappable` object or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> T { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let JSONObject = currentValue else { + throw MapError(key: key, currentValue: currentValue, reason: "Found unexpected nil value", file: file, function: function, line: line) + } + return try Mapper(context: context).mapOrFail(JSONObject: JSONObject) + } + + /// Returns a `BaseMappable` object boxed in `Optional` or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> T? { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let JSONObject = currentValue else { + throw MapError(key: key, currentValue: currentValue, reason: "Found unexpected nil value", file: file, function: function, line: line) + } + return try Mapper(context: context).mapOrFail(JSONObject: JSONObject) + } + + // MARK: [BaseMappable] + + /// Returns a `[BaseMappable]` or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [T] { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let jsonArray = currentValue as? [Any] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[Any]'", file: file, function: function, line: line) + } + + return try jsonArray.map { JSONObject -> T in + return try Mapper(context: context).mapOrFail(JSONObject: JSONObject) + } + } + + /// Returns a `[BaseMappable]` boxed in `Optional` or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [T]? { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let jsonArray = currentValue as? [Any] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[Any]'", file: file, function: function, line: line) + } + + return try jsonArray.map { JSONObject -> T in + return try Mapper(context: context).mapOrFail(JSONObject: JSONObject) + } + } + + /// Returns a `[BaseMappable]` using transform or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", using transform: Transform, file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [Transform.Object] { + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let jsonArray = currentValue as? [Any] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[Any]'", file: file, function: function, line: line) + } + + return try jsonArray.map { json -> Transform.Object in + guard let object = transform.transformFromJSON(json) else { + throw MapError(key: "\(key)", currentValue: json, reason: "Cannot transform to '\(Transform.Object.self)' using \(transform)", file: file, function: function, line: line) + } + return object + } + } + + // MARK: [String: BaseMappable] + + /// Returns a `[String: BaseMappable]` or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [String: T] { + + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let jsonDictionary = currentValue as? [String: Any] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[String: Any]'", file: file, function: function, line: line) + } + return try jsonDictionary.mapValues { json in + return try Mapper(context: context).mapOrFail(JSONObject: json) + } + } + + /// Returns a `[String: BaseMappable]` boxed in `Optional` or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [String: T]? { + + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let jsonDictionary = currentValue as? [String: Any] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[String: Any]'", file: file, function: function, line: line) + } + var value: [String: T] = [:] + for (key, json) in jsonDictionary { + value[key] = try Mapper(context: context).mapOrFail(JSONObject: json) + } + return value + } + + /// Returns a `[String: BaseMappable]` using transform or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", using transform: Transform, file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [String: Transform.Object] { + + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let jsonDictionary = currentValue as? [String: Any] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[String: Any]'", file: file, function: function, line: line) + } + return try jsonDictionary.mapValues { json in + guard let object = transform.transformFromJSON(json) else { + throw MapError(key: key, currentValue: json, reason: "Cannot transform to '\(Transform.Object.self)' using \(transform)", file: file, function: function, line: line) + } + return object + } + } + + /// Returns a `[String: BaseMappable]` using transform or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [[T]]? { + + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let json2DArray = currentValue as? [[Any]] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[[Any]]'", file: file, function: function, line: line) + } + return try json2DArray.map { jsonArray in + try jsonArray.map { jsonObject -> T in + return try Mapper(context: context).mapOrFail(JSONObject: jsonObject) + } + } + } + + // MARK: [[BaseMappable]] + /// Returns a `[[BaseMappable]]` or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [[T]] { + + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let json2DArray = currentValue as? [[Any]] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[[Any]]'", file: file, function: function, line: line) + } + return try json2DArray.map { jsonArray in + try jsonArray.map { jsonObject -> T in + return try Mapper(context: context).mapOrFail(JSONObject: jsonObject) + } + } + } + + /// Returns a `[[BaseMappable]]` using transform or throws an error. + func value(_ key: String, nested: Bool? = nil, delimiter: String = ".", using transform: Transform, file: StaticString = #file, function: StaticString = #function, line: UInt = #line) throws -> [[Transform.Object]] { + + let currentValue = self.currentValue(for: key, nested: nested, delimiter: delimiter) + guard let json2DArray = currentValue as? [[Any]] else { + throw MapError(key: key, currentValue: currentValue, reason: "Cannot cast to '[[Any]]'", + file: file, function: function, line: line) + } + + return try json2DArray.map { jsonArray in + try jsonArray.map { json -> Transform.Object in + guard let object = transform.transformFromJSON(json) else { + throw MapError(key: "\(key)", currentValue: json, reason: "Cannot transform to '\(Transform.Object.self)' using \(transform)", file: file, function: function, line: line) + } + return object + } + } + } +} + +public extension Mapper where N: ImmutableMappable { + + func map(JSON: [String: Any]) throws -> N { + return try self.mapOrFail(JSON: JSON) + } + + func map(JSONString: String) throws -> N { + return try mapOrFail(JSONString: JSONString) + } + + func map(JSONObject: Any) throws -> N { + return try mapOrFail(JSONObject: JSONObject) + } + + // MARK: Array mapping functions + + func mapArray(JSONArray: [[String: Any]]) throws -> [N] { + #if swift(>=4.1) + return try JSONArray.compactMap(mapOrFail) + #else + return try JSONArray.flatMap(mapOrFail) + #endif + } + + func mapArray(JSONString: String) throws -> [N] { + guard let JSONObject = Mapper.parseJSONString(JSONString: JSONString) else { + throw MapError(key: nil, currentValue: JSONString, reason: "Cannot convert string into Any'") + } + + return try mapArray(JSONObject: JSONObject) + } + + func mapArray(JSONObject: Any) throws -> [N] { + guard let JSONArray = JSONObject as? [[String: Any]] else { + throw MapError(key: nil, currentValue: JSONObject, reason: "Cannot cast to '[[String: Any]]'") + } + + return try mapArray(JSONArray: JSONArray) + } + + // MARK: Dictionary mapping functions + + func mapDictionary(JSONString: String) throws -> [String: N] { + guard let JSONObject = Mapper.parseJSONString(JSONString: JSONString) else { + throw MapError(key: nil, currentValue: JSONString, reason: "Cannot convert string into Any'") + } + + return try mapDictionary(JSONObject: JSONObject) + } + + func mapDictionary(JSONObject: Any?) throws -> [String: N] { + guard let JSON = JSONObject as? [String: [String: Any]] else { + throw MapError(key: nil, currentValue: JSONObject, reason: "Cannot cast to '[String: [String: Any]]''") + } + + return try mapDictionary(JSON: JSON) + } + + func mapDictionary(JSON: [String: [String: Any]]) throws -> [String: N] { + return try JSON.filterMap(mapOrFail) + } + + // MARK: Dictinoary of arrays mapping functions + + func mapDictionaryOfArrays(JSONObject: Any?) throws -> [String: [N]] { + guard let JSON = JSONObject as? [String: [[String: Any]]] else { + throw MapError(key: nil, currentValue: JSONObject, reason: "Cannot cast to '[String: [String: Any]]''") + } + return try mapDictionaryOfArrays(JSON: JSON) + } + + func mapDictionaryOfArrays(JSON: [String: [[String: Any]]]) throws -> [String: [N]] { + return try JSON.filterMap { array -> [N] in + try mapArray(JSONArray: array) + } + } + + // MARK: 2 dimentional array mapping functions + + func mapArrayOfArrays(JSONObject: Any?) throws -> [[N]] { + guard let JSONArray = JSONObject as? [[[String: Any]]] else { + throw MapError(key: nil, currentValue: JSONObject, reason: "Cannot cast to '[[[String: Any]]]''") + } + return try JSONArray.map(mapArray) + } + +} + +internal extension Mapper { + + func mapOrFail(JSON: [String: Any]) throws -> N { + let map = Map(mappingType: .fromJSON, JSON: JSON, context: context, shouldIncludeNilValues: shouldIncludeNilValues) + + // Check if object is ImmutableMappable, if so use ImmutableMappable protocol for mapping + if let klass = N.self as? ImmutableMappable.Type, + var object = try klass.init(map: map) as? N { + object.mapping(map: map) + return object + } + + // If not, map the object the standard way + guard let value = self.map(JSON: JSON) else { + throw MapError(key: nil, currentValue: JSON, reason: "Cannot map to '\(N.self)'") + } + return value + } + + func mapOrFail(JSONString: String) throws -> N { + guard let JSON = Mapper.parseJSONStringIntoDictionary(JSONString: JSONString) else { + throw MapError(key: nil, currentValue: JSONString, reason: "Cannot parse into '[String: Any]'") + } + return try mapOrFail(JSON: JSON) + } + + func mapOrFail(JSONObject: Any) throws -> N { + guard let JSON = JSONObject as? [String: Any] else { + throw MapError(key: nil, currentValue: JSONObject, reason: "Cannot cast to '[String: Any]'") + } + return try mapOrFail(JSON: JSON) + } + +} diff --git a/Pods/ObjectMapper/Sources/IntegerOperators.swift b/Pods/ObjectMapper/Sources/IntegerOperators.swift new file mode 100644 index 0000000..6e548d4 --- /dev/null +++ b/Pods/ObjectMapper/Sources/IntegerOperators.swift @@ -0,0 +1,171 @@ +// +// IntegerOperators.swift +// ObjectMapper +// +// Created by Suyeol Jeon on 17/02/2017. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +// MARK: - Signed Integer + +/// SignedInteger mapping +public func <- (left: inout T, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T = toSignedInteger(right.currentValue) ?? 0 + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +/// Optional SignedInteger mapping +public func <- (left: inout T?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T? = toSignedInteger(right.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// ImplicitlyUnwrappedOptional SignedInteger mapping +public func <- (left: inout T!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T! = toSignedInteger(right.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} +#endif + + +// MARK: - Unsigned Integer + +/// UnsignedInteger mapping +public func <- (left: inout T, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T = toUnsignedInteger(right.currentValue) ?? 0 + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + + +/// Optional UnsignedInteger mapping +public func <- (left: inout T?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T? = toUnsignedInteger(right.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// ImplicitlyUnwrappedOptional UnsignedInteger mapping +public func <- (left: inout T!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + let value: T! = toUnsignedInteger(right.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} +#endif + +// MARK: - Casting Utils + +/// Convert any value to `SignedInteger`. +private func toSignedInteger(_ value: Any?) -> T? { + guard + let value = value, + case let number as NSNumber = value + else { + return nil + } + + if T.self == Int.self, let x = Int(exactly: number.int64Value) { + return T.init(x) + } + if T.self == Int8.self, let x = Int8(exactly: number.int64Value) { + return T.init(x) + } + if T.self == Int16.self, let x = Int16(exactly: number.int64Value) { + return T.init(x) + } + if T.self == Int32.self, let x = Int32(exactly: number.int64Value) { + return T.init(x) + } + if T.self == Int64.self, let x = Int64(exactly: number.int64Value) { + return T.init(x) + } + + return nil +} + +/// Convert any value to `UnsignedInteger`. +private func toUnsignedInteger(_ value: Any?) -> T? { + guard + let value = value, + case let number as NSNumber = value + else { + return nil + } + + if T.self == UInt.self, let x = UInt(exactly: number.uint64Value) { + return T.init(x) + } + if T.self == UInt8.self, let x = UInt8(exactly: number.uint64Value) { + return T.init(x) + } + if T.self == UInt16.self, let x = UInt16(exactly: number.uint64Value) { + return T.init(x) + } + if T.self == UInt32.self, let x = UInt32(exactly: number.uint64Value) { + return T.init(x) + } + if T.self == UInt64.self, let x = UInt64(exactly: number.uint64Value) { + return T.init(x) + } + + return nil +} diff --git a/Pods/ObjectMapper/Sources/Map.swift b/Pods/ObjectMapper/Sources/Map.swift new file mode 100644 index 0000000..38dc2a3 --- /dev/null +++ b/Pods/ObjectMapper/Sources/Map.swift @@ -0,0 +1,204 @@ +// +// Map.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2015-10-09. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +import Foundation + +/// MapContext is available for developers who wish to pass information around during the mapping process. +public protocol MapContext { + +} + +/// A class used for holding mapping data +public final class Map { + public let mappingType: MappingType + + public internal(set) var JSON: [String: Any] = [:] + public internal(set) var isKeyPresent = false + public internal(set) var currentValue: Any? + public internal(set) var currentKey: String? + var keyIsNested = false + public internal(set) var nestedKeyDelimiter: String = "." + public var context: MapContext? + public var shouldIncludeNilValues = false /// If this is set to true, toJSON output will include null values for any variables that are not set. + + public let toObject: Bool // indicates whether the mapping is being applied to an existing object + + public init(mappingType: MappingType, JSON: [String: Any], toObject: Bool = false, context: MapContext? = nil, shouldIncludeNilValues: Bool = false) { + + self.mappingType = mappingType + self.JSON = JSON + self.toObject = toObject + self.context = context + self.shouldIncludeNilValues = shouldIncludeNilValues + } + + /// Sets the current mapper value and key. + /// The Key paramater can be a period separated string (ex. "distance.value") to access sub objects. + public subscript(key: String) -> Map { + // save key and value associated to it + return self.subscript(key: key) + } + + public subscript(key: String, delimiter delimiter: String) -> Map { + return self.subscript(key: key, delimiter: delimiter) + } + + public subscript(key: String, nested nested: Bool) -> Map { + return self.subscript(key: key, nested: nested) + } + + public subscript(key: String, nested nested: Bool, delimiter delimiter: String) -> Map { + return self.subscript(key: key, nested: nested, delimiter: delimiter) + } + + public subscript(key: String, ignoreNil ignoreNil: Bool) -> Map { + return self.subscript(key: key, ignoreNil: ignoreNil) + } + + public subscript(key: String, delimiter delimiter: String, ignoreNil ignoreNil: Bool) -> Map { + return self.subscript(key: key, delimiter: delimiter, ignoreNil: ignoreNil) + } + + public subscript(key: String, nested nested: Bool, ignoreNil ignoreNil: Bool) -> Map { + return self.subscript(key: key, nested: nested, ignoreNil: ignoreNil) + } + + public subscript(key: String, nested nested: Bool?, delimiter delimiter: String, ignoreNil ignoreNil: Bool) -> Map { + return self.subscript(key: key, nested: nested, delimiter: delimiter, ignoreNil: ignoreNil) + } + + private func `subscript`(key: String, nested: Bool? = nil, delimiter: String = ".", ignoreNil: Bool = false) -> Map { + // save key and value associated to it + currentKey = key + keyIsNested = nested ?? key.contains(delimiter) + nestedKeyDelimiter = delimiter + + if mappingType == .fromJSON { + // check if a value exists for the current key + // do this pre-check for performance reasons + if keyIsNested { + // break down the components of the key that are separated by delimiter + (isKeyPresent, currentValue) = valueFor(ArraySlice(key.components(separatedBy: delimiter)), dictionary: JSON) + } else { + let object = JSON[key] + let isNSNull = object is NSNull + isKeyPresent = isNSNull ? true : object != nil + currentValue = isNSNull ? nil : object + } + + // update isKeyPresent if ignoreNil is true + if ignoreNil && currentValue == nil { + isKeyPresent = false + } + } + + return self + } + + public func value() -> T? { + let value = currentValue as? T + + // Swift 4.1 breaks Float casting from `NSNumber`. So Added extra checks for `Float` `[Float]` and `[String:Float]` + if value == nil && T.self == Float.self { + if let v = currentValue as? NSNumber { + return v.floatValue as? T + } + } else if value == nil && T.self == [Float].self { + if let v = currentValue as? [Double] { + #if swift(>=4.1) + return v.compactMap{ Float($0) } as? T + #else + return v.flatMap{ Float($0) } as? T + #endif + } + } else if value == nil && T.self == [String:Float].self { + if let v = currentValue as? [String:Double] { + return v.mapValues{ Float($0) } as? T + } + } + return value + } +} + +/// Fetch value from JSON dictionary, loop through keyPathComponents until we reach the desired object +private func valueFor(_ keyPathComponents: ArraySlice, dictionary: [String: Any]) -> (Bool, Any?) { + // Implement it as a tail recursive function. + if keyPathComponents.isEmpty { + return (false, nil) + } + + if let keyPath = keyPathComponents.first { + let isTail = keyPathComponents.count == 1 + let object = dictionary[keyPath] + if object is NSNull { + return (isTail, nil) + } else if keyPathComponents.count > 1, let dict = object as? [String: Any] { + let tail = keyPathComponents.dropFirst() + return valueFor(tail, dictionary: dict) + } else if keyPathComponents.count > 1, let array = object as? [Any] { + let tail = keyPathComponents.dropFirst() + return valueFor(tail, array: array) + } else { + return (isTail && object != nil, object) + } + } + + return (false, nil) +} + +/// Fetch value from JSON Array, loop through keyPathComponents them until we reach the desired object +private func valueFor(_ keyPathComponents: ArraySlice, array: [Any]) -> (Bool, Any?) { + // Implement it as a tail recursive function. + + if keyPathComponents.isEmpty { + return (false, nil) + } + + //Try to convert keypath to Int as index + if let keyPath = keyPathComponents.first, + let index = Int(keyPath) , index >= 0 && index < array.count { + + let isTail = keyPathComponents.count == 1 + let object = array[index] + + if object is NSNull { + return (isTail, nil) + } else if keyPathComponents.count > 1, let array = object as? [Any] { + let tail = keyPathComponents.dropFirst() + return valueFor(tail, array: array) + } else if keyPathComponents.count > 1, let dict = object as? [String: Any] { + let tail = keyPathComponents.dropFirst() + return valueFor(tail, dictionary: dict) + } else { + return (isTail, object) + } + } + + return (false, nil) +} diff --git a/Pods/ObjectMapper/Sources/MapError.swift b/Pods/ObjectMapper/Sources/MapError.swift new file mode 100644 index 0000000..9e9736b --- /dev/null +++ b/Pods/ObjectMapper/Sources/MapError.swift @@ -0,0 +1,68 @@ +// +// MapError.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2016-09-26. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +public struct MapError: Error { + public var key: String? + public var currentValue: Any? + public var reason: String? + public var file: StaticString? + public var function: StaticString? + public var line: UInt? + + public init(key: String?, currentValue: Any?, reason: String?, file: StaticString? = nil, function: StaticString? = nil, line: UInt? = nil) { + self.key = key + self.currentValue = currentValue + self.reason = reason + self.file = file + self.function = function + self.line = line + } +} + +extension MapError: CustomStringConvertible { + + private var location: String? { + guard let file = file, let function = function, let line = line else { return nil } + let fileName = ((String(describing: file).components(separatedBy: "/").last ?? "").components(separatedBy: ".").first ?? "") + return "\(fileName).\(function):\(line)" + } + + public var description: String { + let info: [(String, Any?)] = [ + ("- reason", reason), + ("- location", location), + ("- key", key), + ("- currentValue", currentValue), + ] + let infoString = info.map { "\($0.0): \($0.1 ?? "nil")" }.joined(separator: "\n") + return "Got an error while mapping.\n\(infoString)" + } + +} diff --git a/Pods/ObjectMapper/Sources/Mappable.swift b/Pods/ObjectMapper/Sources/Mappable.swift new file mode 100644 index 0000000..3be7fc1 --- /dev/null +++ b/Pods/ObjectMapper/Sources/Mappable.swift @@ -0,0 +1,136 @@ +// +// Mappable.swift +// ObjectMapper +// +// Created by Scott Hoyt on 10/25/15. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +/// BaseMappable should not be implemented directly. Mappable or StaticMappable should be used instead +public protocol BaseMappable { + /// This function is where all variable mappings should occur. It is executed by Mapper during the mapping (serialization and deserialization) process. + mutating func mapping(map: Map) +} + +public protocol Mappable: BaseMappable { + /// This function can be used to validate JSON prior to mapping. Return nil to cancel mapping at this point + init?(map: Map) +} + +public protocol StaticMappable: BaseMappable { + /// This is function that can be used to: + /// 1) provide an existing cached object to be used for mapping + /// 2) return an object of another class (which conforms to BaseMappable) to be used for mapping. For instance, you may inspect the JSON to infer the type of object that should be used for any given mapping + static func objectForMapping(map: Map) -> BaseMappable? +} + +public extension BaseMappable { + + /// Initializes object from a JSON String + init?(JSONString: String, context: MapContext? = nil) { + if let obj: Self = Mapper(context: context).map(JSONString: JSONString) { + self = obj + } else { + return nil + } + } + + /// Initializes object from a JSON Dictionary + init?(JSON: [String: Any], context: MapContext? = nil) { + if let obj: Self = Mapper(context: context).map(JSON: JSON) { + self = obj + } else { + return nil + } + } + + /// Returns the JSON Dictionary for the object + func toJSON() -> [String: Any] { + return Mapper().toJSON(self) + } + + /// Returns the JSON String for the object + func toJSONString(prettyPrint: Bool = false) -> String? { + return Mapper().toJSONString(self, prettyPrint: prettyPrint) + } +} + +public extension Array where Element: BaseMappable { + + /// Initialize Array from a JSON String + init?(JSONString: String, context: MapContext? = nil) { + if let obj: [Element] = Mapper(context: context).mapArray(JSONString: JSONString) { + self = obj + } else { + return nil + } + } + + /// Initialize Array from a JSON Array + init(JSONArray: [[String: Any]], context: MapContext? = nil) { + let obj: [Element] = Mapper(context: context).mapArray(JSONArray: JSONArray) + self = obj + } + + /// Returns the JSON Array + func toJSON() -> [[String: Any]] { + return Mapper().toJSONArray(self) + } + + /// Returns the JSON String for the object + func toJSONString(prettyPrint: Bool = false) -> String? { + return Mapper().toJSONString(self, prettyPrint: prettyPrint) + } +} + +public extension Set where Element: BaseMappable { + + /// Initializes a set from a JSON String + init?(JSONString: String, context: MapContext? = nil) { + if let obj: Set = Mapper(context: context).mapSet(JSONString: JSONString) { + self = obj + } else { + return nil + } + } + + /// Initializes a set from JSON + init?(JSONArray: [[String: Any]], context: MapContext? = nil) { + guard let obj = Mapper(context: context).mapSet(JSONArray: JSONArray) as Set? else { + return nil + } + self = obj + } + + /// Returns the JSON Set + func toJSON() -> [[String: Any]] { + return Mapper().toJSONSet(self) + } + + /// Returns the JSON String for the object + func toJSONString(prettyPrint: Bool = false) -> String? { + return Mapper().toJSONString(self, prettyPrint: prettyPrint) + } +} diff --git a/Pods/ObjectMapper/Sources/Mapper.swift b/Pods/ObjectMapper/Sources/Mapper.swift new file mode 100755 index 0000000..cccbdce --- /dev/null +++ b/Pods/ObjectMapper/Sources/Mapper.swift @@ -0,0 +1,491 @@ +// +// Mapper.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-09. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +public enum MappingType { + case fromJSON + case toJSON +} + +/// The Mapper class provides methods for converting Model objects to JSON and methods for converting JSON to Model objects +public final class Mapper { + + public var context: MapContext? + public var shouldIncludeNilValues = false /// If this is set to true, toJSON output will include null values for any variables that are not set. + + public init(context: MapContext? = nil, shouldIncludeNilValues: Bool = false){ + self.context = context + self.shouldIncludeNilValues = shouldIncludeNilValues + } + + // MARK: Mapping functions that map to an existing object toObject + + /// Maps a JSON object to an existing Mappable object if it is a JSON dictionary, or returns the passed object as is + public func map(JSONObject: Any?, toObject object: N) -> N { + if let JSON = JSONObject as? [String: Any] { + return map(JSON: JSON, toObject: object) + } + + return object + } + + /// Map a JSON string onto an existing object + public func map(JSONString: String, toObject object: N) -> N { + if let JSON = Mapper.parseJSONStringIntoDictionary(JSONString: JSONString) { + return map(JSON: JSON, toObject: object) + } + return object + } + + /// Maps a JSON dictionary to an existing object that conforms to Mappable. + /// Usefull for those pesky objects that have crappy designated initializers like NSManagedObject + public func map(JSON: [String: Any], toObject object: N) -> N { + var mutableObject = object + let map = Map(mappingType: .fromJSON, JSON: JSON, toObject: true, context: context, shouldIncludeNilValues: shouldIncludeNilValues) + mutableObject.mapping(map: map) + return mutableObject + } + + //MARK: Mapping functions that create an object + + /// Map a JSON string to an object that conforms to Mappable + public func map(JSONString: String) -> N? { + if let JSON = Mapper.parseJSONStringIntoDictionary(JSONString: JSONString) { + return map(JSON: JSON) + } + + return nil + } + + /// Maps a JSON object to a Mappable object if it is a JSON dictionary or NSString, or returns nil. + public func map(JSONObject: Any?) -> N? { + if let JSON = JSONObject as? [String: Any] { + return map(JSON: JSON) + } + + return nil + } + + /// Maps a JSON dictionary to an object that conforms to Mappable + public func map(JSON: [String: Any]) -> N? { + let map = Map(mappingType: .fromJSON, JSON: JSON, context: context, shouldIncludeNilValues: shouldIncludeNilValues) + + if let klass = N.self as? StaticMappable.Type { // Check if object is StaticMappable + if var object = klass.objectForMapping(map: map) as? N { + object.mapping(map: map) + return object + } + } else if let klass = N.self as? Mappable.Type { // Check if object is Mappable + if var object = klass.init(map: map) as? N { + object.mapping(map: map) + return object + } + } else if let klass = N.self as? ImmutableMappable.Type { // Check if object is ImmutableMappable + do { + if var object = try klass.init(map: map) as? N { + object.mapping(map: map) + return object + } + } catch let error { + #if DEBUG + let exception: NSException + if let mapError = error as? MapError { + exception = NSException(name: .init(rawValue: "MapError"), reason: mapError.description, userInfo: nil) + } else { + exception = NSException(name: .init(rawValue: "ImmutableMappableError"), reason: error.localizedDescription, userInfo: nil) + } + exception.raise() + #endif + } + } else { + // Ensure BaseMappable is not implemented directly + assert(false, "BaseMappable should not be implemented directly. Please implement Mappable, StaticMappable or ImmutableMappable") + } + + return nil + } + + // MARK: Mapping functions for Arrays and Dictionaries + + /// Maps a JSON array to an object that conforms to Mappable + public func mapArray(JSONString: String) -> [N]? { + let parsedJSON: Any? = Mapper.parseJSONString(JSONString: JSONString) + + if let objectArray = mapArray(JSONObject: parsedJSON) { + return objectArray + } + + // failed to parse JSON into array form + // try to parse it into a dictionary and then wrap it in an array + if let object = map(JSONObject: parsedJSON) { + return [object] + } + + return nil + } + + /// Maps a JSON object to an array of Mappable objects if it is an array of JSON dictionary, or returns nil. + public func mapArray(JSONObject: Any?) -> [N]? { + if let JSONArray = JSONObject as? [[String: Any]] { + return mapArray(JSONArray: JSONArray) + } + + return nil + } + + /// Maps an array of JSON dictionary to an array of Mappable objects + public func mapArray(JSONArray: [[String: Any]]) -> [N] { + // map every element in JSON array to type N + #if swift(>=4.1) + let result = JSONArray.compactMap(map) + #else + let result = JSONArray.flatMap(map) + #endif + return result + } + + /// Maps a JSON object to a dictionary of Mappable objects if it is a JSON dictionary of dictionaries, or returns nil. + public func mapDictionary(JSONString: String) -> [String: N]? { + let parsedJSON: Any? = Mapper.parseJSONString(JSONString: JSONString) + return mapDictionary(JSONObject: parsedJSON) + } + + /// Maps a JSON object to a dictionary of Mappable objects if it is a JSON dictionary of dictionaries, or returns nil. + public func mapDictionary(JSONObject: Any?) -> [String: N]? { + if let JSON = JSONObject as? [String: [String: Any]] { + return mapDictionary(JSON: JSON) + } + + return nil + } + + /// Maps a JSON dictionary of dictionaries to a dictionary of Mappable objects + public func mapDictionary(JSON: [String: [String: Any]]) -> [String: N]? { + // map every value in dictionary to type N + let result = JSON.filterMap(map) + if !result.isEmpty { + return result + } + + return nil + } + + /// Maps a JSON object to a dictionary of Mappable objects if it is a JSON dictionary of dictionaries, or returns nil. + public func mapDictionary(JSONObject: Any?, toDictionary dictionary: [String: N]) -> [String: N] { + if let JSON = JSONObject as? [String : [String : Any]] { + return mapDictionary(JSON: JSON, toDictionary: dictionary) + } + + return dictionary + } + + /// Maps a JSON dictionary of dictionaries to an existing dictionary of Mappable objects + public func mapDictionary(JSON: [String: [String: Any]], toDictionary dictionary: [String: N]) -> [String: N] { + var mutableDictionary = dictionary + for (key, value) in JSON { + if let object = dictionary[key] { + _ = map(JSON: value, toObject: object) + } else { + mutableDictionary[key] = map(JSON: value) + } + } + + return mutableDictionary + } + + /// Maps a JSON object to a dictionary of arrays of Mappable objects + public func mapDictionaryOfArrays(JSONObject: Any?) -> [String: [N]]? { + if let JSON = JSONObject as? [String: [[String: Any]]] { + return mapDictionaryOfArrays(JSON: JSON) + } + + return nil + } + + ///Maps a JSON dictionary of arrays to a dictionary of arrays of Mappable objects + public func mapDictionaryOfArrays(JSON: [String: [[String: Any]]]) -> [String: [N]]? { + // map every value in dictionary to type N + let result = JSON.filterMap { + mapArray(JSONArray: $0) + } + + if !result.isEmpty { + return result + } + + return nil + } + + /// Maps an 2 dimentional array of JSON dictionaries to a 2 dimentional array of Mappable objects + public func mapArrayOfArrays(JSONObject: Any?) -> [[N]]? { + if let JSONArray = JSONObject as? [[[String: Any]]] { + let objectArray = JSONArray.map { innerJSONArray in + return mapArray(JSONArray: innerJSONArray) + } + + if !objectArray.isEmpty { + return objectArray + } + } + + return nil + } + + // MARK: Utility functions for converting strings to JSON objects + + /// Convert a JSON String into a Dictionary using NSJSONSerialization + public static func parseJSONStringIntoDictionary(JSONString: String) -> [String: Any]? { + let parsedJSON: Any? = Mapper.parseJSONString(JSONString: JSONString) + return parsedJSON as? [String: Any] + } + + /// Convert a JSON String into an Object using NSJSONSerialization + public static func parseJSONString(JSONString: String) -> Any? { + let data = JSONString.data(using: String.Encoding.utf8, allowLossyConversion: true) + if let data = data { + let parsedJSON: Any? + do { + parsedJSON = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) + } catch let error { + print(error) + parsedJSON = nil + } + return parsedJSON + } + + return nil + } +} + +extension Mapper { + // MARK: Functions that create model from JSON file + + /// JSON file to Mappable object + /// - parameter JSONfile: Filename + /// - Returns: Mappable object + public func map(JSONfile: String) -> N? { + if let path = Bundle.main.path(forResource: JSONfile, ofType: nil) { + do { + let JSONString = try String(contentsOfFile: path) + do { + return self.map(JSONString: JSONString) + } + } catch { + return nil + } + } + return nil + } + + /// JSON file to Mappable object array + /// - parameter JSONfile: Filename + /// - Returns: Mappable object array + public func mapArray(JSONfile: String) -> [N]? { + if let path = Bundle.main.path(forResource: JSONfile, ofType: nil) { + do { + let JSONString = try String(contentsOfFile: path) + do { + return self.mapArray(JSONString: JSONString) + } + } catch { + return nil + } + } + return nil + } +} + +extension Mapper { + + // MARK: Functions that create JSON from objects + + ///Maps an object that conforms to Mappable to a JSON dictionary + public func toJSON(_ object: N) -> [String: Any] { + var mutableObject = object + let map = Map(mappingType: .toJSON, JSON: [:], context: context, shouldIncludeNilValues: shouldIncludeNilValues) + mutableObject.mapping(map: map) + return map.JSON + } + + ///Maps an array of Objects to an array of JSON dictionaries [[String: Any]] + public func toJSONArray(_ array: [N]) -> [[String: Any]] { + return array.map { + // convert every element in array to JSON dictionary equivalent + self.toJSON($0) + } + } + + ///Maps a dictionary of Objects that conform to Mappable to a JSON dictionary of dictionaries. + public func toJSONDictionary(_ dictionary: [String: N]) -> [String: [String: Any]] { + return dictionary.map { (arg: (key: String, value: N)) in + // convert every value in dictionary to its JSON dictionary equivalent + return (arg.key, self.toJSON(arg.value)) + } + } + + ///Maps a dictionary of Objects that conform to Mappable to a JSON dictionary of dictionaries. + public func toJSONDictionaryOfArrays(_ dictionary: [String: [N]]) -> [String: [[String: Any]]] { + return dictionary.map { (arg: (key: String, value: [N])) in + // convert every value (array) in dictionary to its JSON dictionary equivalent + return (arg.key, self.toJSONArray(arg.value)) + } + } + + /// Maps an Object to a JSON string with option of pretty formatting + public func toJSONString(_ object: N, prettyPrint: Bool = false) -> String? { + let JSONDict = toJSON(object) + + return Mapper.toJSONString(JSONDict as Any, prettyPrint: prettyPrint) + } + + /// Maps an array of Objects to a JSON string with option of pretty formatting + public func toJSONString(_ array: [N], prettyPrint: Bool = false) -> String? { + let JSONDict = toJSONArray(array) + + return Mapper.toJSONString(JSONDict as Any, prettyPrint: prettyPrint) + } + + /// Converts an Object to a JSON string with option of pretty formatting + public static func toJSONString(_ JSONObject: Any, prettyPrint: Bool) -> String? { + let options: JSONSerialization.WritingOptions = prettyPrint ? .prettyPrinted : [] + if let JSON = Mapper.toJSONData(JSONObject, options: options) { + return String(data: JSON, encoding: String.Encoding.utf8) + } + + return nil + } + + /// Converts an Object to JSON data with options + public static func toJSONData(_ JSONObject: Any, options: JSONSerialization.WritingOptions) -> Data? { + if JSONSerialization.isValidJSONObject(JSONObject) { + let JSONData: Data? + do { + JSONData = try JSONSerialization.data(withJSONObject: JSONObject, options: options) + } catch let error { + print(error) + JSONData = nil + } + + return JSONData + } + + return nil + } +} + +extension Mapper where N: Hashable { + + /// Maps a JSON array to an object that conforms to Mappable + public func mapSet(JSONString: String) -> Set? { + let parsedJSON: Any? = Mapper.parseJSONString(JSONString: JSONString) + + if let objectArray = mapArray(JSONObject: parsedJSON) { + return Set(objectArray) + } + + // failed to parse JSON into array form + // try to parse it into a dictionary and then wrap it in an array + if let object = map(JSONObject: parsedJSON) { + return Set([object]) + } + + return nil + } + + /// Maps a JSON object to an Set of Mappable objects if it is an array of JSON dictionary, or returns nil. + public func mapSet(JSONObject: Any?) -> Set? { + if let JSONArray = JSONObject as? [[String: Any]] { + return mapSet(JSONArray: JSONArray) + } + + return nil + } + + /// Maps an Set of JSON dictionary to an array of Mappable objects + public func mapSet(JSONArray: [[String: Any]]) -> Set { + // map every element in JSON array to type N + #if swift(>=4.1) + return Set(JSONArray.compactMap(map)) + #else + return Set(JSONArray.flatMap(map)) + #endif + } + + ///Maps a Set of Objects to a Set of JSON dictionaries [[String : Any]] + public func toJSONSet(_ set: Set) -> [[String: Any]] { + return set.map { + // convert every element in set to JSON dictionary equivalent + self.toJSON($0) + } + } + + /// Maps a set of Objects to a JSON string with option of pretty formatting + public func toJSONString(_ set: Set, prettyPrint: Bool = false) -> String? { + let JSONDict = toJSONSet(set) + + return Mapper.toJSONString(JSONDict as Any, prettyPrint: prettyPrint) + } +} + +extension Dictionary { + internal func map(_ f: (Element) throws -> (K, V)) rethrows -> [K: V] { + var mapped = [K: V]() + + for element in self { + let newElement = try f(element) + mapped[newElement.0] = newElement.1 + } + + return mapped + } + + internal func map(_ f: (Element) throws -> (K, [V])) rethrows -> [K: [V]] { + var mapped = [K: [V]]() + + for element in self { + let newElement = try f(element) + mapped[newElement.0] = newElement.1 + } + + return mapped + } + + + internal func filterMap(_ f: (Value) throws -> U?) rethrows -> [Key: U] { + var mapped = [Key: U]() + + for (key, value) in self { + if let newValue = try f(value) { + mapped[key] = newValue + } + } + + return mapped + } +} diff --git a/Pods/ObjectMapper/Sources/NSDecimalNumberTransform.swift b/Pods/ObjectMapper/Sources/NSDecimalNumberTransform.swift new file mode 100644 index 0000000..d06a4b9 --- /dev/null +++ b/Pods/ObjectMapper/Sources/NSDecimalNumberTransform.swift @@ -0,0 +1,52 @@ +// +// TransformOf.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 8/22/16. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class NSDecimalNumberTransform: TransformType { + public typealias Object = NSDecimalNumber + public typealias JSON = String + + public init() {} + + open func transformFromJSON(_ value: Any?) -> NSDecimalNumber? { + if let string = value as? String { + return NSDecimalNumber(string: string) + } else if let number = value as? NSNumber { + return NSDecimalNumber(decimal: number.decimalValue) + } else if let double = value as? Double { + return NSDecimalNumber(floatLiteral: double) + } + return nil + } + + open func transformToJSON(_ value: NSDecimalNumber?) -> String? { + guard let value = value else { return nil } + return value.description + } +} diff --git a/Pods/ObjectMapper/Sources/Operators.swift b/Pods/ObjectMapper/Sources/Operators.swift new file mode 100755 index 0000000..2c12c52 --- /dev/null +++ b/Pods/ObjectMapper/Sources/Operators.swift @@ -0,0 +1,398 @@ +// +// Operators.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-09. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/** +* This file defines a new operator which is used to create a mapping between an object and a JSON key value. +* There is an overloaded operator definition for each type of object that is supported in ObjectMapper. +* This provides a way to add custom logic to handle specific types of objects +*/ + +/// Operator used for defining mappings to and from JSON +infix operator <- + +/// Operator used to define mappings to JSON +infix operator >>> + +// MARK:- Objects with Basic types + +/// Object of Basic type +public func <- (left: inout T, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.basicType(&left, object: right.value()) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: T, right: Map) { + if right.mappingType == .toJSON { + ToJSON.basicType(left, map: right) + } +} + + +/// Optional object of basic type +public func <- (left: inout T?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalBasicType(&left, object: right.value()) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: T?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalBasicType(left, map: right) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped optional object of basic type +public func <- (left: inout T!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalBasicType(&left, object: right.value()) + case .toJSON: + left >>> right + default: () + } +} +#endif + +// MARK:- Mappable Objects - + +/// Object conforming to Mappable +public func <- (left: inout T, right: Map) { + switch right.mappingType { + case .fromJSON: + FromJSON.object(&left, map: right) + case .toJSON: + left >>> right + } +} + +public func >>> (left: T, right: Map) { + if right.mappingType == .toJSON { + ToJSON.object(left, map: right) + } +} + + +/// Optional Mappable objects +public func <- (left: inout T?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObject(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: T?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalObject(left, map: right) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped optional Mappable objects +public func <- (left: inout T!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObject(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} +#endif + +// MARK:- Dictionary of Mappable objects - Dictionary + +/// Dictionary of Mappable objects +public func <- (left: inout Dictionary, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.objectDictionary(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Dictionary, right: Map) { + if right.mappingType == .toJSON { + ToJSON.objectDictionary(left, map: right) + } +} + + +/// Optional Dictionary of Mappable object +public func <- (left: inout Dictionary?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectDictionary(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Dictionary?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalObjectDictionary(left, map: right) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped Optional Dictionary of Mappable object +public func <- (left: inout Dictionary!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectDictionary(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} +#endif + +/// Dictionary of Mappable objects +public func <- (left: inout Dictionary, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.objectDictionaryOfArrays(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Dictionary, right: Map) { + if right.mappingType == .toJSON { + ToJSON.objectDictionaryOfArrays(left, map: right) + } +} + +/// Optional Dictionary of Mappable object +public func <- (left: inout Dictionary?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectDictionaryOfArrays(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Dictionary?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalObjectDictionaryOfArrays(left, map: right) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped Optional Dictionary of Mappable object +public func <- (left: inout Dictionary!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectDictionaryOfArrays(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} +#endif + +// MARK:- Array of Mappable objects - Array + +/// Array of Mappable objects +public func <- (left: inout Array, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.objectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array, right: Map) { + if right.mappingType == .toJSON { + ToJSON.objectArray(left, map: right) + } +} + +/// Optional array of Mappable objects +public func <- (left: inout Array?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalObjectArray(left, map: right) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped Optional array of Mappable objects +public func <- (left: inout Array!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} +#endif + +// MARK:- Array of Array of Mappable objects - Array> + +/// Array of Array Mappable objects +public func <- (left: inout Array>, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.twoDimensionalObjectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array>, right: Map) { + if right.mappingType == .toJSON { + ToJSON.twoDimensionalObjectArray(left, map: right) + } +} + + +/// Optional array of Mappable objects +public func <- (left:inout Array>?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalTwoDimensionalObjectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array>?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalTwoDimensionalObjectArray(left, map: right) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped Optional array of Mappable objects +public func <- (left: inout Array>!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalTwoDimensionalObjectArray(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} +#endif + +// MARK:- Set of Mappable objects - Set + +/// Set of Mappable objects +public func <- (left: inout Set, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.objectSet(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Set, right: Map) { + if right.mappingType == .toJSON { + ToJSON.objectSet(left, map: right) + } +} + + +/// Optional Set of Mappable objects +public func <- (left: inout Set?, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectSet(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Set?, right: Map) { + if right.mappingType == .toJSON { + ToJSON.optionalObjectSet(left, map: right) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped Optional Set of Mappable objects +public func <- (left: inout Set!, right: Map) { + switch right.mappingType { + case .fromJSON where right.isKeyPresent: + FromJSON.optionalObjectSet(&left, map: right) + case .toJSON: + left >>> right + default: () + } +} +#endif diff --git a/Pods/ObjectMapper/Sources/ToJSON.swift b/Pods/ObjectMapper/Sources/ToJSON.swift new file mode 100644 index 0000000..674db27 --- /dev/null +++ b/Pods/ObjectMapper/Sources/ToJSON.swift @@ -0,0 +1,177 @@ +// +// ToJSON.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-13. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +private func setValue(_ value: Any, map: Map) { + setValue(value, key: map.currentKey!, checkForNestedKeys: map.keyIsNested, delimiter: map.nestedKeyDelimiter, dictionary: &map.JSON) +} + +private func setValue(_ value: Any, key: String, checkForNestedKeys: Bool, delimiter: String, dictionary: inout [String : Any]) { + if checkForNestedKeys { + let keyComponents = ArraySlice(key.components(separatedBy: delimiter).filter { !$0.isEmpty }.map { $0 }) + setValue(value, forKeyPathComponents: keyComponents, dictionary: &dictionary) + } else { + dictionary[key] = value + } +} + +private func setValue(_ value: Any, forKeyPathComponents components: ArraySlice, dictionary: inout [String : Any]) { + guard let head = components.first else { + return + } + + let headAsString = String(head) + if components.count == 1 { + dictionary[headAsString] = value + } else { + var child = dictionary[headAsString] as? [String : Any] ?? [:] + + let tail = components.dropFirst() + setValue(value, forKeyPathComponents: tail, dictionary: &child) + + dictionary[headAsString] = child + } +} + +internal final class ToJSON { + + class func basicType(_ field: N, map: Map) { + if let x = field as Any? , false + || x is NSNumber // Basic types + || x is Bool + || x is Int + || x is Double + || x is Float + || x is String + || x is NSNull + || x is Array // Arrays + || x is Array + || x is Array + || x is Array + || x is Array + || x is Array + || x is Array + || x is Array> + || x is Dictionary // Dictionaries + || x is Dictionary + || x is Dictionary + || x is Dictionary + || x is Dictionary + || x is Dictionary + || x is Dictionary + { + setValue(x, map: map) + } + } + + class func optionalBasicType(_ field: N?, map: Map) { + if let field = field { + basicType(field, map: map) + } else if map.shouldIncludeNilValues { + basicType(NSNull(), map: map) //If BasicType is nil, emit NSNull into the JSON output + } + } + + class func object(_ field: N, map: Map) { + if let result = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSON(field) as Any? { + setValue(result, map: map) + } + } + + class func optionalObject(_ field: N?, map: Map) { + if let field = field { + object(field, map: map) + } else if map.shouldIncludeNilValues { + basicType(NSNull(), map: map) //If field is nil, emit NSNull into the JSON output + } + } + + class func objectArray(_ field: Array, map: Map) { + let JSONObjects = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSONArray(field) + + setValue(JSONObjects, map: map) + } + + class func optionalObjectArray(_ field: Array?, map: Map) { + if let field = field { + objectArray(field, map: map) + } + } + + class func twoDimensionalObjectArray(_ field: Array>, map: Map) { + var array = [[[String: Any]]]() + for innerArray in field { + let JSONObjects = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSONArray(innerArray) + array.append(JSONObjects) + } + setValue(array, map: map) + } + + class func optionalTwoDimensionalObjectArray(_ field: Array>?, map: Map) { + if let field = field { + twoDimensionalObjectArray(field, map: map) + } + } + + class func objectSet(_ field: Set, map: Map) { + let JSONObjects = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSONSet(field) + + setValue(JSONObjects, map: map) + } + + class func optionalObjectSet(_ field: Set?, map: Map) { + if let field = field { + objectSet(field, map: map) + } + } + + class func objectDictionary(_ field: Dictionary, map: Map) { + let JSONObjects = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSONDictionary(field) + + setValue(JSONObjects, map: map) + } + + class func optionalObjectDictionary(_ field: Dictionary?, map: Map) { + if let field = field { + objectDictionary(field, map: map) + } + } + + class func objectDictionaryOfArrays(_ field: Dictionary, map: Map) { + let JSONObjects = Mapper(context: map.context, shouldIncludeNilValues: map.shouldIncludeNilValues).toJSONDictionaryOfArrays(field) + + setValue(JSONObjects, map: map) + } + + class func optionalObjectDictionaryOfArrays(_ field: Dictionary?, map: Map) { + if let field = field { + objectDictionaryOfArrays(field, map: map) + } + } +} diff --git a/Pods/ObjectMapper/Sources/TransformOf.swift b/Pods/ObjectMapper/Sources/TransformOf.swift new file mode 100644 index 0000000..6012260 --- /dev/null +++ b/Pods/ObjectMapper/Sources/TransformOf.swift @@ -0,0 +1,48 @@ +// +// TransformOf.swift +// ObjectMapper +// +// Created by Syo Ikeda on 1/23/15. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +open class TransformOf: TransformType { + public typealias Object = ObjectType + public typealias JSON = JSONType + + private let fromJSON: (JSONType?) -> ObjectType? + private let toJSON: (ObjectType?) -> JSONType? + + public init(fromJSON: @escaping(JSONType?) -> ObjectType?, toJSON: @escaping(ObjectType?) -> JSONType?) { + self.fromJSON = fromJSON + self.toJSON = toJSON + } + + open func transformFromJSON(_ value: Any?) -> ObjectType? { + return fromJSON(value as? JSONType) + } + + open func transformToJSON(_ value: ObjectType?) -> JSONType? { + return toJSON(value) + } +} diff --git a/Pods/ObjectMapper/Sources/TransformOperators.swift b/Pods/ObjectMapper/Sources/TransformOperators.swift new file mode 100644 index 0000000..1c55f9b --- /dev/null +++ b/Pods/ObjectMapper/Sources/TransformOperators.swift @@ -0,0 +1,709 @@ +// +// TransformOperators.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2016-09-26. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +// MARK:- Transforms + +/// Object of Basic type with Transform +public func <- (left: inout Transform.Object, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value = transform.transformFromJSON(map.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Transform.Object, right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON { + let value: Transform.JSON? = transform.transformToJSON(left) + ToJSON.optionalBasicType(value, map: map) + } +} + + +/// Optional object of basic type with Transform +public func <- (left: inout Transform.Object?, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value = transform.transformFromJSON(map.currentValue) + FromJSON.optionalBasicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Transform.Object?, right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON { + let value: Transform.JSON? = transform.transformToJSON(left) + ToJSON.optionalBasicType(value, map: map) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped optional object of basic type with Transform +public func <- (left: inout Transform.Object!, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value = transform.transformFromJSON(map.currentValue) + FromJSON.optionalBasicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} +#endif + +/// Array of Basic type with Transform +public func <- (left: inout [Transform.Object], right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONArrayWithTransform(map.currentValue, transform: transform) + FromJSON.basicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: [Transform.Object], right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON{ + let values = toJSONArrayWithTransform(left, transform: transform) + ToJSON.optionalBasicType(values, map: map) + } +} + + +/// Optional array of Basic type with Transform +public func <- (left: inout [Transform.Object]?, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONArrayWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: [Transform.Object]?, right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON { + let values = toJSONArrayWithTransform(left, transform: transform) + ToJSON.optionalBasicType(values, map: map) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped optional array of Basic type with Transform +public func <- (left: inout [Transform.Object]!, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONArrayWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} +#endif + +/// Dictionary of Basic type with Transform +public func <- (left: inout [String: Transform.Object], right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONDictionaryWithTransform(map.currentValue, transform: transform) + FromJSON.basicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: [String: Transform.Object], right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == . toJSON { + let values = toJSONDictionaryWithTransform(left, transform: transform) + ToJSON.optionalBasicType(values, map: map) + } +} + + +/// Optional dictionary of Basic type with Transform +public func <- (left: inout [String: Transform.Object]?, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONDictionaryWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: [String: Transform.Object]?, right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON { + let values = toJSONDictionaryWithTransform(left, transform: transform) + ToJSON.optionalBasicType(values, map: map) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped optional dictionary of Basic type with Transform +public func <- (left: inout [String: Transform.Object]!, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let values = fromJSONDictionaryWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: values) + case .toJSON: + left >>> right + default: () + } +} +#endif + +// MARK:- Transforms of Mappable Objects - + +/// Object conforming to Mappable that have transforms +public func <- (left: inout Transform.Object, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value: Transform.Object? = transform.transformFromJSON(map.currentValue) + FromJSON.basicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Transform.Object, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let value: Transform.JSON? = transform.transformToJSON(left) + ToJSON.optionalBasicType(value, map: map) + } +} + + +/// Optional Mappable objects that have transforms +public func <- (left: inout Transform.Object?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value: Transform.Object? = transform.transformFromJSON(map.currentValue) + FromJSON.optionalBasicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Transform.Object?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON{ + let value: Transform.JSON? = transform.transformToJSON(left) + ToJSON.optionalBasicType(value, map: map) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped optional Mappable objects that have transforms +public func <- (left: inout Transform.Object!, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let value: Transform.Object? = transform.transformFromJSON(map.currentValue) + FromJSON.optionalBasicType(&left, object: value) + case .toJSON: + left >>> right + default: () + } +} +#endif + + +// MARK:- Dictionary of Mappable objects with a transform - Dictionary + +/// Dictionary of Mappable objects with a transform +public func <- (left: inout Dictionary, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .fromJSON && map.isKeyPresent, + let object = map.currentValue as? [String: Any] { + let value = fromJSONDictionaryWithTransform(object as Any?, transform: transform) ?? left + FromJSON.basicType(&left, object: value) + } else if map.mappingType == .toJSON { + left >>> right + } +} + +public func >>> (left: Dictionary, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let value = toJSONDictionaryWithTransform(left, transform: transform) + ToJSON.basicType(value, map: map) + } +} + + +/// Optional Dictionary of Mappable object with a transform +public func <- (left: inout Dictionary?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .fromJSON && map.isKeyPresent, let object = map.currentValue as? [String : Any]{ + let value = fromJSONDictionaryWithTransform(object as Any?, transform: transform) ?? left + FromJSON.optionalBasicType(&left, object: value) + } else if map.mappingType == .toJSON { + left >>> right + } +} + +public func >>> (left: Dictionary?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let value = toJSONDictionaryWithTransform(left, transform: transform) + ToJSON.optionalBasicType(value, map: map) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped Optional Dictionary of Mappable object with a transform +public func <- (left: inout Dictionary!, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .fromJSON && map.isKeyPresent, let dictionary = map.currentValue as? [String : Any]{ + let transformedDictionary = fromJSONDictionaryWithTransform(dictionary as Any?, transform: transform) ?? left + FromJSON.optionalBasicType(&left, object: transformedDictionary) + } else if map.mappingType == .toJSON { + left >>> right + } +} +#endif + +/// Dictionary of Mappable objects with a transform +public func <- (left: inout Dictionary, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + + if let dictionary = map.currentValue as? [String : [Any]], map.mappingType == .fromJSON && map.isKeyPresent { + let transformedDictionary = dictionary.map { (arg: (key: String, values: [Any])) -> (String, [Transform.Object]) in + let (key, values) = arg + if let jsonArray = fromJSONArrayWithTransform(values, transform: transform) { + return (key, jsonArray) + } + if let leftValue = left[key] { + return (key, leftValue) + } + return (key, []) + } + + FromJSON.basicType(&left, object: transformedDictionary) + } else if map.mappingType == .toJSON { + left >>> right + } +} + +public func >>> (left: Dictionary, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + + if map.mappingType == .toJSON { + + let transformedDictionary = left.map { (arg: (key: String, value: [Transform.Object])) in + return (arg.key, toJSONArrayWithTransform(arg.value, transform: transform) ?? []) + } + + ToJSON.basicType(transformedDictionary, map: map) + } +} + + +/// Optional Dictionary of Mappable object with a transform +public func <- (left: inout Dictionary?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + + if let dictionary = map.currentValue as? [String : [Any]], map.mappingType == .fromJSON && map.isKeyPresent { + + let transformedDictionary = dictionary.map { (arg: (key: String, values: [Any])) -> (String, [Transform.Object]) in + let (key, values) = arg + if let jsonArray = fromJSONArrayWithTransform(values, transform: transform) { + return (key, jsonArray) + } + if let leftValue = left?[key] { + return (key, leftValue) + } + return (key, []) + } + + FromJSON.optionalBasicType(&left, object: transformedDictionary) + } else if map.mappingType == .toJSON { + left >>> right + } +} + +public func >>> (left: Dictionary?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + + if map.mappingType == .toJSON { + let transformedDictionary = left?.map { (arg: (key: String, values: [Transform.Object])) in + return (arg.key, toJSONArrayWithTransform(arg.values, transform: transform) ?? []) + } + + ToJSON.optionalBasicType(transformedDictionary, map: map) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped Optional Dictionary of Mappable object with a transform +public func <- (left: inout Dictionary!, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + + if let dictionary = map.currentValue as? [String : [Any]], map.mappingType == .fromJSON && map.isKeyPresent { + let transformedDictionary = dictionary.map { (arg: (key: String, values: [Any])) -> (String, [Transform.Object]) in + let (key, values) = arg + if let jsonArray = fromJSONArrayWithTransform(values, transform: transform) { + return (key, jsonArray) + } + if let leftValue = left?[key] { + return (key, leftValue) + } + return (key, []) + } + FromJSON.optionalBasicType(&left, object: transformedDictionary) + } else if map.mappingType == .toJSON { + left >>> right + } +} +#endif + +// MARK:- Array of Mappable objects with transforms - Array + +/// Array of Mappable objects +public func <- (left: inout Array, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + if let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) { + FromJSON.basicType(&left, object: transformedValues) + } + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let transformedValues = toJSONArrayWithTransform(left, transform: transform) + ToJSON.optionalBasicType(transformedValues, map: map) + } +} + + +/// Optional array of Mappable objects +public func <- (left: inout Array?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: transformedValues) + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Array?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let transformedValues = toJSONArrayWithTransform(left, transform: transform) + ToJSON.optionalBasicType(transformedValues, map: map) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped Optional array of Mappable objects +public func <- (left: inout Array!, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) + FromJSON.optionalBasicType(&left, object: transformedValues) + case .toJSON: + left >>> right + default: () + } +} +#endif + +// MARK:- Array of Array of objects - Array>> with transforms + +/// Array of Array of objects with transform +public func <- (left: inout [[Transform.Object]], right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .toJSON: + left >>> right + case .fromJSON where map.isKeyPresent: + guard let original2DArray = map.currentValue as? [[Any]] else { break } + #if swift(>=4.1) + let transformed2DArray = original2DArray.compactMap { values in + fromJSONArrayWithTransform(values as Any?, transform: transform) + } + #else + let transformed2DArray = original2DArray.flatMap { values in + fromJSONArrayWithTransform(values as Any?, transform: transform) + } + #endif + FromJSON.basicType(&left, object: transformed2DArray) + default: + break + } +} + +public func >>> (left: [[Transform.Object]], right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON{ + #if swift(>=4.1) + let transformed2DArray = left.compactMap { values in + toJSONArrayWithTransform(values, transform: transform) + } + #else + let transformed2DArray = left.flatMap { values in + toJSONArrayWithTransform(values, transform: transform) + } + #endif + ToJSON.basicType(transformed2DArray, map: map) + } +} + +/// Optional array of array of objects with transform +public func <- (left: inout [[Transform.Object]]?, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .toJSON: + left >>> right + case .fromJSON where map.isKeyPresent: + guard let original2DArray = map.currentValue as? [[Any]] else { break } + #if swift(>=4.1) + let transformed2DArray = original2DArray.compactMap { values in + fromJSONArrayWithTransform(values as Any?, transform: transform) + } + #else + let transformed2DArray = original2DArray.flatMap { values in + fromJSONArrayWithTransform(values as Any?, transform: transform) + } + #endif + FromJSON.optionalBasicType(&left, object: transformed2DArray) + default: + break + } +} + +public func >>> (left: [[Transform.Object]]?, right: (Map, Transform)) { + let (map, transform) = right + if map.mappingType == .toJSON { + #if swift(>=4.1) + let transformed2DArray = left?.compactMap { values in + toJSONArrayWithTransform(values, transform: transform) + } + #else + let transformed2DArray = left?.flatMap { values in + toJSONArrayWithTransform(values, transform: transform) + } + #endif + ToJSON.optionalBasicType(transformed2DArray, map: map) + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped Optional array of array of objects with transform +public func <- (left: inout [[Transform.Object]]!, right: (Map, Transform)) { + let (map, transform) = right + switch map.mappingType { + case .toJSON: + left >>> right + case .fromJSON where map.isKeyPresent: + guard let original2DArray = map.currentValue as? [[Any]] else { break } + #if swift(>=4.1) + let transformed2DArray = original2DArray.compactMap { values in + fromJSONArrayWithTransform(values as Any?, transform: transform) + } + #else + let transformed2DArray = original2DArray.flatMap { values in + fromJSONArrayWithTransform(values as Any?, transform: transform) + } + #endif + FromJSON.optionalBasicType(&left, object: transformed2DArray) + default: + break + } +} +#endif + +// MARK:- Set of Mappable objects with a transform - Set + +/// Set of Mappable objects with transform +public func <- (left: inout Set, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + if let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) { + FromJSON.basicType(&left, object: Set(transformedValues)) + } + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Set, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + let transformedValues = toJSONArrayWithTransform(Array(left), transform: transform) + ToJSON.optionalBasicType(transformedValues, map: map) + } +} + + +/// Optional Set of Mappable objects with transform +public func <- (left: inout Set?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + if let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) { + FromJSON.basicType(&left, object: Set(transformedValues)) + } + case .toJSON: + left >>> right + default: () + } +} + +public func >>> (left: Set?, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + if map.mappingType == .toJSON { + if let values = left { + let transformedValues = toJSONArrayWithTransform(Array(values), transform: transform) + ToJSON.optionalBasicType(transformedValues, map: map) + } + } +} + + +// Code targeting the Swift 4.1 compiler and below. +#if !(swift(>=4.1.50) || (swift(>=3.4) && !swift(>=4.0))) +/// Implicitly unwrapped Optional set of Mappable objects with transform +public func <- (left: inout Set!, right: (Map, Transform)) where Transform.Object: BaseMappable { + let (map, transform) = right + switch map.mappingType { + case .fromJSON where map.isKeyPresent: + if let transformedValues = fromJSONArrayWithTransform(map.currentValue, transform: transform) { + FromJSON.basicType(&left, object: Set(transformedValues)) + } + case .toJSON: + left >>> right + default: () + } +} +#endif + + +private func fromJSONArrayWithTransform(_ input: Any?, transform: Transform) -> [Transform.Object]? { + if let values = input as? [Any] { + #if swift(>=4.1) + return values.compactMap { value in + return transform.transformFromJSON(value) + } + #else + return values.flatMap { value in + return transform.transformFromJSON(value) + } + #endif + } else { + return nil + } +} + +private func fromJSONDictionaryWithTransform(_ input: Any?, transform: Transform) -> [String: Transform.Object]? { + if let values = input as? [String: Any] { + return values.filterMap { value in + return transform.transformFromJSON(value) + } + } else { + return nil + } +} + +private func toJSONArrayWithTransform(_ input: [Transform.Object]?, transform: Transform) -> [Transform.JSON]? { + #if swift(>=4.1) + return input?.compactMap { value in + return transform.transformToJSON(value) + } + #else + return input?.flatMap { value in + return transform.transformToJSON(value) + } + #endif +} + +private func toJSONDictionaryWithTransform(_ input: [String: Transform.Object]?, transform: Transform) -> [String: Transform.JSON]? { + return input?.filterMap { value in + return transform.transformToJSON(value) + } +} diff --git a/Pods/ObjectMapper/Sources/TransformType.swift b/Pods/ObjectMapper/Sources/TransformType.swift new file mode 100644 index 0000000..5daf0d3 --- /dev/null +++ b/Pods/ObjectMapper/Sources/TransformType.swift @@ -0,0 +1,35 @@ +// +// TransformType.swift +// ObjectMapper +// +// Created by Syo Ikeda on 2/4/15. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +public protocol TransformType { + associatedtype Object + associatedtype JSON + + func transformFromJSON(_ value: Any?) -> Object? + func transformToJSON(_ value: Object?) -> JSON? +} diff --git a/Pods/ObjectMapper/Sources/URLTransform.swift b/Pods/ObjectMapper/Sources/URLTransform.swift new file mode 100644 index 0000000..1e8bbb2 --- /dev/null +++ b/Pods/ObjectMapper/Sources/URLTransform.swift @@ -0,0 +1,67 @@ +// +// URLTransform.swift +// ObjectMapper +// +// Created by Tristan Himmelman on 2014-10-27. +// +// The MIT License (MIT) +// +// Copyright (c) 2014-2018 Tristan Himmelman +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import Foundation + +open class URLTransform: TransformType { + public typealias Object = URL + public typealias JSON = String + private let shouldEncodeURLString: Bool + private let allowedCharacterSet: CharacterSet + + /** + Initializes the URLTransform with an option to encode URL strings before converting them to an NSURL + - parameter shouldEncodeUrlString: when true (the default) the string is encoded before passing + to `NSURL(string:)` + - returns: an initialized transformer + */ + public init(shouldEncodeURLString: Bool = false, allowedCharacterSet: CharacterSet = .urlQueryAllowed) { + self.shouldEncodeURLString = shouldEncodeURLString + self.allowedCharacterSet = allowedCharacterSet + } + + open func transformFromJSON(_ value: Any?) -> URL? { + guard let URLString = value as? String else { return nil } + + if !shouldEncodeURLString { + return URL(string: URLString) + } + + guard let escapedURLString = URLString.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) else { + return nil + } + return URL(string: escapedURLString) + } + + open func transformToJSON(_ value: URL?) -> String? { + if let URL = value { + return URL.absoluteString + } + return nil + } +} diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj new file mode 100644 index 0000000..da9cb34 --- /dev/null +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -0,0 +1,3485 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 00271C40AF1CFB935EC252DC984E552D /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 00BE49C726548FF41D71F0AD2F2624B6 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 016D4F6D0512E0659937DB5D9A7C5384 /* Alamofire-watchOS-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 8632EDFC946676A1D1A292794D61D782 /* Alamofire-watchOS-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 01C9772E1A5DE079E7FBC2D7FE6152F3 /* PBKDF1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 422CC1C0934FE7FC948E3569428B35ED /* PBKDF1.swift */; }; + 01CAEC5F6F9431E4D251A35A36F6A9EE /* TaskDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5058D4CAD4BA5182249468FCE66189B8 /* TaskDelegate.swift */; }; + 0281DB230A246653CBFC06716D26833C /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3127E182056505DD5B33AD124A8F6B1 /* Request.swift */; }; + 04B00E068A79A5DD6B0485F38928B785 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = D34F2E10923BD125CC6DAA118EAA5435 /* NSData+ImageContentType.m */; }; + 0531358ED3EEA7DA09D4A1434463D3BD /* AEADChaCha20Poly1305.swift in Sources */ = {isa = PBXBuildFile; fileRef = F094557EED3C2FD9C3C689756D00C385 /* AEADChaCha20Poly1305.swift */; }; + 06E003B32DF139847C7FF7B143AA5211 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EA2B9E7598C53E3DB0F929D091814F0 /* ImageIO.framework */; }; + 07A83E7FDC67DC07531437F3B2429F9C /* SDWebImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6551AC70A6402369433BA24C84E9A435 /* SDWebImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 081919834624DA9CC57286E7058729C9 /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EC1117E36EC72700C886B6C907A7408 /* SDWebImageManager.m */; }; + 083C363C26AA6B89D057D3D78964FB5E /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 1664B5B9254FBFC12EFAD7F013FE6970 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 098072C1CC99DE5810FE1609F1FF3F15 /* AEAD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A0C06C72AC2BB4DA4355BAA129F8BF /* AEAD.swift */; }; + 0A9B4D606A95D72A06EBD5DBE512442F /* Poly1305.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC8CAF1B4E8684CEC2A1DD43A2CD3B4F /* Poly1305.swift */; }; + 0B86CB58612CC8E19C34E34C7C9A5655 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA160AA3138E9D4CCFBF58278868FD65 /* Foundation.framework */; }; + 0BD66FAA67A327E7DDD184F40EC99076 /* ParameterEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 245CFE0D7E98B32922BCC4E1D7A71809 /* ParameterEncoding.swift */; }; + 0CD7DB3813871C92BC9A4D2257548455 /* ChaCha20.swift in Sources */ = {isa = PBXBuildFile; fileRef = A379D3C523FB33338113A30BD5AE4148 /* ChaCha20.swift */; }; + 0D1CFE37DDE9FA2C68AA4732ABEC59F9 /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 81502D6196EAB1D8EDDF3FF070D40A05 /* UIImage+ForceDecode.m */; }; + 0D69C28600D92940039DAAB37F45E48B /* SecureBytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B77F90AF101152500DC0C09450E3BE07 /* SecureBytes.swift */; }; + 0E6F1A0D418690C97ADD49EDAA3897E5 /* Pods-BSRadioWaves-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = BC5525591C4639FA428EAEB065CE90DD /* Pods-BSRadioWaves-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0E95F909D3EC1C4EE448A9C78DFA7DCF /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 35D46D44A4A590E3E369C91F5AD26C87 /* UIView+WebCacheOperation.m */; }; + 0EAB0E9ACA5D88F58AA2A2C02D593EB4 /* CompactMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C64A422373DB6A64CB548996A5CD141 /* CompactMap.swift */; }; + 0F7BDECDD56B33D440AE53E632594FA2 /* ResponseSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33941F96D2513278A5F2225BC00F4B18 /* ResponseSerialization.swift */; }; + 0FA012BA03ADB4916413EBD05967348C /* UInt16+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23CB7AD01B3AEF46B5390A8C2168CF21 /* UInt16+Extension.swift */; }; + 101FDC1EA6AA25642A56000BD82A334F /* Bit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEDF7D8385F0270E5D3BC9E10F3B0E1 /* Bit.swift */; }; + 1053A51877CBF516A6DE82C3C4933FB0 /* CryptoSwift-iOS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 21FBF47F8C9900718A5776DB63DBF696 /* CryptoSwift-iOS-dummy.m */; }; + 11BA51468C6BEBB50D3B42D5DD0DB2FE /* NSButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = B78C1CBD3175E21DEA630033F390D15B /* NSButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 11FDC1963D6CDC1B520B4AA792132DEB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E163351D4E2C8D729AA52C9E28A394FE /* Foundation.framework */; }; + 121F2D109820CA5800F300E7CF97FBC7 /* Poly1305.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC8CAF1B4E8684CEC2A1DD43A2CD3B4F /* Poly1305.swift */; }; + 12CEE670DF63F6C2AE4E2568A4628DBB /* PKCS7Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 205B852C5AEA3938C4D0682669465ABC /* PKCS7Padding.swift */; }; + 1334657041B050C16C12845B29EE07E7 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799EBBE8EA9380002541B3BDC2509DFA /* Operators.swift */; }; + 13452BD15063340D3611D43BEB1F5180 /* FromJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D31C620E17F575E6E2F90BC9D2A29AC /* FromJSON.swift */; }; + 1350592B2C2AD5C48612BF939DF2A947 /* PKCS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCDF52BDB380C340B3D3DAE01DF1FD66 /* PKCS5.swift */; }; + 13D4ACAB3F0392D7263702403F4C4C77 /* MultipartFormData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4136293AF5C2A5645461EBE3091D1C6 /* MultipartFormData.swift */; }; + 149A8E4C500AC240AFA3375ACEC6D739 /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CD26E0EC964DBCE766401B9E13A32F /* SDWebImageDownloaderOperation.m */; }; + 158A572BA530B879969A463DAC72E471 /* BlockCipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0E31F7478A5D3CC1E0F67F71531EE /* BlockCipher.swift */; }; + 15AC30A00CE77675A4056CA8275DD59D /* CBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F45D8ABEEC2A98771C4E897DAFC6A4 /* CBC.swift */; }; + 16A529D53801C06C358DCF0CCB76BEA9 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB5CE6CC897D348D068D5DB80E1B6EC /* String+Extension.swift */; }; + 1765073CE326EF43C6EE2DA39EEF0CD9 /* Collection+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D60B50A48DA2FE4BEC4632019494C5B /* Collection+Extension.swift */; }; + 183F3DD9433855E6E8BD250389AF5490 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 943077C55D579E24267EC6C5B0454DFD /* SDImageCache.m */; }; + 1909DF830712BD9329650FD08237EFDC /* AEADChaCha20Poly1305.swift in Sources */ = {isa = PBXBuildFile; fileRef = F094557EED3C2FD9C3C689756D00C385 /* AEADChaCha20Poly1305.swift */; }; + 193A61B46B136D8CE523CFB4994E623B /* CipherModeWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 908B397C63C8C34F165CAD8E07B2B429 /* CipherModeWorker.swift */; }; + 1969B263630CA265C10336D7BA1FAB3E /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 757FF0BF3BF390A8D5EA34773154614D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 19DC365B1810400A707E80F25800CE2F /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E576DE9C1B8474304A4A7807AE657421 /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1CC6530ED1A250FB08C5882CE508A02B /* StreamDecryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773C7DCD3A6D2C43B7F7FEA7F3D4D25A /* StreamDecryptor.swift */; }; + 1DD06E247F72CDCFFA1AEEF11F5087CA /* SDWebImageImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2762DCE84D02C12B44357EF970B68C /* SDWebImageImageIOCoder.m */; }; + 1ED564129D44BA0F9377E0576E1E859B /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = E2C55A5F184670CD2D61B8ACC7D22EA7 /* UIView+WebCache.m */; }; + 1F1FDA2C0DCBA6DB3151DA3213DE53C8 /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DB9CD2F0897EAF9893BF859B2D73C22 /* SDWebImageCompat.m */; }; + 1F815330CE9D869EE23CDAB57FE96921 /* TransformOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47CD592978CC4B92452ADA4ABBAB4803 /* TransformOperators.swift */; }; + 2024EE5E265681137A9FEBC630E6E0F1 /* Toast-Swift-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 84FE771131293A9CF3CC3B1F6B3BE5D5 /* Toast-Swift-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 209330C37BEC7FAC01804014E708EE5A /* PBKDF2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 425747501EF0C921813B08642430C109 /* PBKDF2.swift */; }; + 20DF8618EB52318E1E409E7950251B8A /* UInt128.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53094347E1ABA3120D3AD1AA9180D872 /* UInt128.swift */; }; + 2280D5D148C48C58E4221FCA14ACDBC3 /* SHA1.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C5C58AD00C41F3B2BAE57C718CE33D /* SHA1.swift */; }; + 228FBB88050A6A43ED63E5A246FA5B79 /* CBCMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6F47AD390E6C7ABB618D40AFCECBE0 /* CBCMAC.swift */; }; + 22B974F6D8AE91C7EBB281BA295BFDED /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A46A7D9CED5FA4156C5A1DE790FEC3C /* SDImageCacheConfig.m */; }; + 23FC3D80C6D35D07CD1ADD7153A6AC97 /* Mapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8548C09A1A91E9A78E396912E7341AC /* Mapper.swift */; }; + 251092C90608B134761700CA7A7C9B72 /* NSButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DE20B76C04AA5CF2B9733747FA8611F /* NSButton+WebCache.m */; }; + 259D02D2D2E5BC2695795D70FEA1CD6E /* DateFormatterTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = F135091FE0197253E94F3A7A342CDF58 /* DateFormatterTransform.swift */; }; + 2639C366DD45C5C06CA83D99DBAA39E7 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D817A21EC4523EBBBD1C2D8E17CED11 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 266520AC43ED9DF12A683A99F5E9C3E5 /* BlockModeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C26871F2127DFE55454DFB49C28A3FF /* BlockModeOptions.swift */; }; + 26A738B4C8DD72611403735CFA0F4F4A /* SHA2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BCBF8BD04E98F16D5391D774A4D5C1 /* SHA2.swift */; }; + 2796A50CEB957A8B6F87FFB1F5144873 /* Bit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEDF7D8385F0270E5D3BC9E10F3B0E1 /* Bit.swift */; }; + 27CC4E8B16E46E400437A10F13994AC5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA160AA3138E9D4CCFBF58278868FD65 /* Foundation.framework */; }; + 29134B8B1D648CFD82BFD8681DA80AFC /* AES.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5775FAC65F3B1EDD0EDA8737972FB2 /* AES.swift */; }; + 2A6384DF808EF5DEACF2BEDE85DE1122 /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 61CB331B8CD0303E2231784911D66A13 /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2E17D9A43A2E54513B66E7CFDC64FCF7 /* Updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9720BAAF7DC2D2F0AC082B1A100BC164 /* Updatable.swift */; }; + 2EC66BF077ECDCADC7A590740DF631DC /* HexColorTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA95DDF2A57AADC3E6B6647C6A5F39F /* HexColorTransform.swift */; }; + 2ECBC16CCB9AF65A0E7E9CAE58EB0EBF /* MD5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C1556FAF37B97DFB2249475C26CAB5 /* MD5.swift */; }; + 2EF5A6F5A7BEB727E439F7D8644A91A8 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 926E31D5ADF72105FA3C33197139C3D2 /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 2F3A7727F25809D20B4D5115D64F545A /* Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA052F80295C9ADE2DEBDCD35A7D8B8C /* Alamofire.swift */; }; + 2FE23977B15D0922051184A46056425B /* UInt8+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D25864C51D6CCE0C9E1EF1442594EEA /* UInt8+Extension.swift */; }; + 31288D2789EA9FCE04805CDFC16168CB /* CustomDateFormatTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB7A5ADD204B71124FE48C814E42B27F /* CustomDateFormatTransform.swift */; }; + 330C04EB6B7EBC2003CD24A79A08D54A /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA2EE4ABF8769574D46F419F7513E7D /* HMAC.swift */; }; + 33BB727FB0183B19924B416F1D002EA3 /* SDWebImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D1A15C0955F3655BC85CE5A74E77F47A /* SDWebImageCodersManager.m */; }; + 340D5C77FD74AEC59AF2A8C4F1B102D4 /* NoPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B044125FB9727CC592AF1BFF2CC2F2 /* NoPadding.swift */; }; + 34ABAAEAC7EE9C4385762FB7C166C4B6 /* DataTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B38173AAE3F4E4D4C374AA2AAF68276 /* DataTransform.swift */; }; + 351C9E0999DBBD3039305453571B4CAF /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 378FDDCE9E13EB010D91074AB4C18BF5 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 35AE5CBE8D974F9CF5D38BB642F897B0 /* EnumTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE948AF72E43DA87B86E6EE34844AA7 /* EnumTransform.swift */; }; + 35E1DEB2C8EF2909085BAD583DE3227F /* Utils+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0DA179FAD7A331AED02CEE24C70925 /* Utils+Foundation.swift */; }; + 368229A1AF8392BFEF77534F67B242F5 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A0CC2ACCC6BB85FABA3E21D2428AEFA /* ImageIO.framework */; }; + 3722ACD41FB5DC82551D8C9D67913A6B /* UIImageView+HighlightedWebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 00BE49C726548FF41D71F0AD2F2624B6 /* UIImageView+HighlightedWebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 382047EE1CDB7D26194BCCCC8F779A50 /* OFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE4572688292058D24E25808BFB7F214 /* OFB.swift */; }; + 387B9B2271DBD4A689CE452A83552AFA /* DictionaryTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525C256AAFECE92A936CF2F90CD41B14 /* DictionaryTransform.swift */; }; + 38BF185C5AAF151790AA556C9A302873 /* TransformType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5EC70BFF0AB9EE7D13152B0E1ABE1C /* TransformType.swift */; }; + 38FB0E7C2F07D0640CA816C3E4E7F740 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF19C129E29A610DB4B377B99E06B9C /* UIButton+WebCache.m */; }; + 39C27E5EB9E2DF685D7C901DD497DEDB /* String+FoundationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58706E4731DB31F7E51958134686A6EF /* String+FoundationExtension.swift */; }; + 3A2973BBB1EDAC4D6245B04D23900C3C /* ToJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41CE0E198552CF07557A00D4F80C0F36 /* ToJSON.swift */; }; + 3A658CB4FD7BA8211392A42DF64748A3 /* PKCS7.swift in Sources */ = {isa = PBXBuildFile; fileRef = 446A03A259525DA90A1935D4F9C81A9C /* PKCS7.swift */; }; + 3AB990FDF4FCA4090651180F1325B815 /* SessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FB7555B50165984CBBB4A22E2E1425 /* SessionDelegate.swift */; }; + 3AF4444EFD5EC930D252D8CE042A57BE /* DictionaryTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525C256AAFECE92A936CF2F90CD41B14 /* DictionaryTransform.swift */; }; + 3AF5A66E94A640FE0D7F5A8E4791FF0B /* AES+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C15A47D715F6B15E5149A633B9C36EFE /* AES+Foundation.swift */; }; + 3BB297A8AE0B782713C81CA176C92A3A /* HexColorTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA95DDF2A57AADC3E6B6647C6A5F39F /* HexColorTransform.swift */; }; + 3C001B71C94B9E90FDFBF9D594A42ACA /* Cryptors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E05B6BBEC2DFE3C8152FA0893EF346B /* Cryptors.swift */; }; + 3C32046F5D649BFBABD868F717EBFDCD /* SDAnimatedImageRep.h in Headers */ = {isa = PBXBuildFile; fileRef = 389F6AE412BA3442C610F7AE0823BE3D /* SDAnimatedImageRep.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3C824072FCB242031FCE0F0DF2DB9A59 /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397A89A1E00B8670B3F71320935E1342 /* Cipher.swift */; }; + 3D02F66096398ED3952DFDD526A4A6F9 /* CryptoSwift-watchOS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 14F4FD10BB7A334B3B52ED6E3664ECC3 /* CryptoSwift-watchOS-dummy.m */; }; + 3D1ABD34F6BAFA66CAAD4E0BAB945E27 /* UInt32+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBA93C0676F4CFA61B1FC6FD7912934C /* UInt32+Extension.swift */; }; + 3D468C0815E3A6AD6CA5D1FF6888AAEB /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F4663658088190E2706E86A72103A64 /* SDWebImageFrame.m */; }; + 3D7620A75375E0E74DDAB0981BAEB064 /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 914A98F250AD776F45A885D1B3D91DE0 /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3FE9D5BA3BD766A36EBD01744DB78A99 /* IntegerOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CDCE9F4E104ACC626EEEF1A601E4CD /* IntegerOperators.swift */; }; + 4000B140B0CEC176DCBFEED2F111D340 /* Digest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F57F121D9B91B455E018464D636FE /* Digest.swift */; }; + 40513DA063AEC8135574BCD3C651DD94 /* NSImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C1A9A84A5151F6158459DBB5A1F72D5 /* NSImage+WebCache.m */; }; + 4208B4C5B873E595AB329242ED1E4DC4 /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = F23837990984900FE72488992448FDAC /* UIImageView+WebCache.m */; }; + 4416B6EF81FA316E311A2CB14A750E59 /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 89F55E53A7E33823B2E6DD656AE2D71F /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4453055474E17318AAEB2334C7667B92 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 6609A66E0D47DCD51DB0589EA61119C3 /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 44B648F9466A039EA185A9B435330884 /* Generics.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF8325A35C0DCE5CBE4E54CB9076259 /* Generics.swift */; }; + 451FB27A7555760099E5B2C1AF2844C3 /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0E1D8BB5A80DEE7944B70EBD304267 /* SessionManager.swift */; }; + 456F5AB16DE22E601CA5EB4200088DD0 /* AFError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DF89231999CD17564BBD2E53963AE6E /* AFError.swift */; }; + 45E6DA0D9A897FC4AF1A2BD354D7596D /* MapError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87E6C9F2F10891B6C1D7116A2E3CD8B9 /* MapError.swift */; }; + 4628A632B1ED82AD170EAE18F83D6B5E /* ECB.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3483723D40955DEACECCC483FB9AC7 /* ECB.swift */; }; + 4682F8666DB6D570CBFE49E9E853B21A /* CBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08F45D8ABEEC2A98771C4E897DAFC6A4 /* CBC.swift */; }; + 471E0B5164CFD1AE905CE8624DCBCAA8 /* HKDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = B488C5F5836A8E73CFC8CA67FDEF982D /* HKDF.swift */; }; + 4753716AE7A1AB22FB6BA61AA74D942F /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028CE532624E25B101754545D1387E07 /* Toast.swift */; }; + 48D720BA973F7303DC3030D02345A89D /* SecureBytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = B77F90AF101152500DC0C09450E3BE07 /* SecureBytes.swift */; }; + 495FE1474EB2181D16F1D6BCAB1CF2C6 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE4A55F1AB2AFA507296B580FEC587C /* Response.swift */; }; + 49B7962FEEB34E5815E36EB7BDEC705B /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = E3D5C30DCE7867365039FD693D17E6D1 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4AC172969396B67FC872C8569ADEE5EF /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0C50437972D72F88FBD1569D9F259D /* Array+Extension.swift */; }; + 4AD74B38ED3F019D40994B16DD6BCA06 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAEBB50390AA61AD781599F0627E4C4B /* Operators.swift */; }; + 4C83C1F54714ACFB4B695E513A2BB1B3 /* Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42505EEE9F52E1B31ED6A637B15D7383 /* Validation.swift */; }; + 4C9D0AB942C6B5C2DF95B3A4E2EEE9EC /* SDWebImage-watchOS-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 43FB744D3A7CA2381CF940DFC5A5FD7F /* SDWebImage-watchOS-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4CE4A9C57F0DE9DF2CF65F63D68B6FEB /* Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA052F80295C9ADE2DEBDCD35A7D8B8C /* Alamofire.swift */; }; + 4D220E8AB887166036114C207C23EB27 /* Blowfish+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C3BC66B278570FFDEE73352885A4CC /* Blowfish+Foundation.swift */; }; + 506E22EADDEEED8CFF3E38C1F0E08BC8 /* StreamEncryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D2FFE8BB73DE0387C92C95013346E7 /* StreamEncryptor.swift */; }; + 5088A386549E488BF0877FE6A4BB2FAA /* Collection+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D60B50A48DA2FE4BEC4632019494C5B /* Collection+Extension.swift */; }; + 51835F4DBA7535D3B273EC544DA0BD60 /* PBKDF1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 422CC1C0934FE7FC948E3569428B35ED /* PBKDF1.swift */; }; + 51BD479F01C6053255A3DEC67D681CCC /* ZeroPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB0407015DEE2575F91C4C608D1B686D /* ZeroPadding.swift */; }; + 52238EC162F664F6A4E5D1E744C6BFCF /* UIImage+ForceDecode.m in Sources */ = {isa = PBXBuildFile; fileRef = 81502D6196EAB1D8EDDF3FF070D40A05 /* UIImage+ForceDecode.m */; }; + 528E81E182861836E3CE7E4057649C4E /* UInt32+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBA93C0676F4CFA61B1FC6FD7912934C /* UInt32+Extension.swift */; }; + 52B20FDB0201028D86307F9946EBF8EF /* UInt128.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53094347E1ABA3120D3AD1AA9180D872 /* UInt128.swift */; }; + 52EBC9A20D621DC61F5EC609E18A2A95 /* CTR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B1C8CC6167248D84957B7ADA1E0244 /* CTR.swift */; }; + 530D331BD4A81AE8DAE49D35B345D9FB /* BlockEncryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F662A585BB28AE3557F5C0968A8144A /* BlockEncryptor.swift */; }; + 532CFEA5CEDB2C143A4903C1DBEF99DB /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E40BD236BFB5823682FB0FE1E7E15BD /* Map.swift */; }; + 534CE6051A9CB5086D6A19383738EE5A /* SDWebImageFrame.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F4663658088190E2706E86A72103A64 /* SDWebImageFrame.m */; }; + 546323B71CA763DE815B4955EE3F2064 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472B024F353D47204165DCAEAF286DCF /* Result.swift */; }; + 546CF5C1DD38A2FDFBC185F1C3A2BF3E /* DateFormatterTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = F135091FE0197253E94F3A7A342CDF58 /* DateFormatterTransform.swift */; }; + 550D8614A47C99CCE668BFD0AB127879 /* Cryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24C0980CBE1EFBEF2247F08C12724914 /* Cryptor.swift */; }; + 554388F18CCBC9BEF055514CF53E9413 /* Rabbit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3B80E4AF948917D76BC73171318A007 /* Rabbit.swift */; }; + 5555FEBD264545E23926244CA9227C78 /* DateTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D15C250294C4B5E1EE5502CD51CD0B3 /* DateTransform.swift */; }; + 555CCE7489DCA14A8820185B1112D9A9 /* CBCMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B6F47AD390E6C7ABB618D40AFCECBE0 /* CBCMAC.swift */; }; + 55FB3669E7D1C8B5C8DA456E4C568E8B /* SDWebImageCodersManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6551AC70A6402369433BA24C84E9A435 /* SDWebImageCodersManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5706F9D06ADDDD84552008140D8D3230 /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 89F8D45050B050498DEEB1FE8142B1ED /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5839BD02D33AEEDD6B9D1BF39B2F8D9E /* BlockDecryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4887F39F9288BCE0542FEDF35B09ACB3 /* BlockDecryptor.swift */; }; + 59AC5DB9C43DA74449B73E06F10AF537 /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = BCED4393BF6FB333978C434865EE9FBC /* SDAnimatedImageRep.m */; }; + 59B09F25C480FA889EE6C6F69C8BE2CA /* ChaCha20.swift in Sources */ = {isa = PBXBuildFile; fileRef = A379D3C523FB33338113A30BD5AE4148 /* ChaCha20.swift */; }; + 59E350D6402F1CF88B07555C252A2352 /* ImmutableMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47804D2377F9E25533891D9B9C72C58A /* ImmutableMappable.swift */; }; + 5A4410AFFAE7F5039CC9161F49C04038 /* AlamofireObjectMapper-iOS-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = F1218EBF99FA63A965FB34486DB7C7F3 /* AlamofireObjectMapper-iOS-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5AEE5105937ECF29037067F3EABCB37A /* ObjectMapper-iOS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 145A91E809AD1CE2702E3F4069A17127 /* ObjectMapper-iOS-dummy.m */; }; + 5B038F87B1FD86C4ADD0A2B0DA18643C /* TransformType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B5EC70BFF0AB9EE7D13152B0E1ABE1C /* TransformType.swift */; }; + 5C7DF7CB1BA993BA5CCB8E6CC73CFE61 /* CustomDateFormatTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB7A5ADD204B71124FE48C814E42B27F /* CustomDateFormatTransform.swift */; }; + 5CB34F05FD5BA8236759368A58008493 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 492E42E49BAE2DDE8F7F547356939396 /* UIImage+MultiFormat.m */; }; + 5CBB7CEC836EF2FF32D704C54CDAB879 /* CompactMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C64A422373DB6A64CB548996A5CD141 /* CompactMap.swift */; }; + 5CE203E4D16F633214A031EF544278F0 /* Pods-BSRadioWaves-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F67BA910C156D91489B8E49AC6550B7F /* Pods-BSRadioWaves-dummy.m */; }; + 5DC223206D9E0964E6D1E700896661BC /* ServerTrustPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0F4A73853B69418C200A0180A7FC4DB /* ServerTrustPolicy.swift */; }; + 5DC57AE11E0C4752497A7462AEEDF2CD /* Pods-Watch Extension-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = F77DAE94554B83C00E063A5804930878 /* Pods-Watch Extension-dummy.m */; }; + 5DF7A8F8D41D428EB9BBFA6BB3A45FC2 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = CBD91AC822910EC52639A4A2C7358026 /* SDWebImagePrefetcher.m */; }; + 5EB2768C011DE9C8FE837773AA73CD07 /* UIButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 926E31D5ADF72105FA3C33197139C3D2 /* UIButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6051FE9A068EC8298411D6007BB357A7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA160AA3138E9D4CCFBF58278868FD65 /* Foundation.framework */; }; + 60EA59B5146F9FB15AAFF20FF32387B0 /* UIImage+ForceDecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 1664B5B9254FBFC12EFAD7F013FE6970 /* UIImage+ForceDecode.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 611AB64AB4C84F5F8E2380A43345E351 /* SDAnimatedImageRep.h in Headers */ = {isa = PBXBuildFile; fileRef = 389F6AE412BA3442C610F7AE0823BE3D /* SDAnimatedImageRep.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 61436F06ECBFF3AA5F51E4146ACDF7FE /* CFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 790FEA4A05DD92EE9916842AF2EDD8C3 /* CFB.swift */; }; + 6144D447A7DAD552A07FE7F2EE5DB664 /* HMAC+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47841E0B2A196904B1250178233B0C29 /* HMAC+Foundation.swift */; }; + 617A4B2BC36A71E862EB0C8A93990120 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = D6509D88F413480F9B11247D7A31549A /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6251CAC2A279363E07554B3A8DA2CA80 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FB5CE6CC897D348D068D5DB80E1B6EC /* String+Extension.swift */; }; + 65479167C9E2EC75681DE5FE2F1D49FF /* EnumOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6016CF43C0B2D31043ADD65889FBB42 /* EnumOperators.swift */; }; + 66600C86BB2CF249F5C34343311573C0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E163351D4E2C8D729AA52C9E28A394FE /* Foundation.framework */; }; + 670AB4D559C4E66CF0B60B27C0DE2646 /* DispatchQueue+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2BF12B2417E7E9CA801120E04FB7E /* DispatchQueue+Alamofire.swift */; }; + 670E976777CE44A3F4BF59950C2055DB /* SDAnimatedImageRep.m in Sources */ = {isa = PBXBuildFile; fileRef = BCED4393BF6FB333978C434865EE9FBC /* SDAnimatedImageRep.m */; }; + 67554580402C7300A860AF9563FC3A6F /* NSData+ImageContentType.h in Headers */ = {isa = PBXBuildFile; fileRef = 89F8D45050B050498DEEB1FE8142B1ED /* NSData+ImageContentType.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 676E149D31AF6FCB7C7AE88825D88B55 /* UIImage+MemoryCacheCost.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AEC4674D34D88026D83CC62A515512B /* UIImage+MemoryCacheCost.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 67C5BAF5A9E17BFDE623472406575D6A /* BatchedCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0312205F7DFEECFAA5D36AA6DB32459 /* BatchedCollection.swift */; }; + 67F01BB8E113750A7C0DA9E918D8D57D /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D502B6FDF14EB7F9077C2048BB9117F /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 67F8FAACADDD58958FB8A0364C009600 /* Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E40BD236BFB5823682FB0FE1E7E15BD /* Map.swift */; }; + 6820FC9C4AEE3F77DD0E587E4600A9E9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA160AA3138E9D4CCFBF58278868FD65 /* Foundation.framework */; }; + 6823E48E063CE19E4C605DE25E26E70E /* GCM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F1237FA10AC9A3ECB0203D8A4DF99A1 /* GCM.swift */; }; + 6932867F7689135CBD9ADF5FC3F5A6A0 /* Array+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C66354493DBECB5149CAB1B8BAE892E /* Array+Foundation.swift */; }; + 69D3DD7100C6F6572F8750F383B18F6B /* AES.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5775FAC65F3B1EDD0EDA8737972FB2 /* AES.swift */; }; + 6A6D0CECC921FB6D30A6C4686F47B346 /* URLTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67340A7EFCE654D4C23EAF007F66C19E /* URLTransform.swift */; }; + 6B326644BB08AEDF697A82A0F1A66D68 /* Toast-Swift-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = DC509E11825E5D0085456E6886E813C1 /* Toast-Swift-dummy.m */; }; + 6CB0DE96D5AD0C23CF4ABC303BB01513 /* BlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4486FDC523F6036877D028ACC7575A91 /* BlockMode.swift */; }; + 6CB2C8A094A3B452C6BFC8E2999DDAA7 /* BlockEncryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F662A585BB28AE3557F5C0968A8144A /* BlockEncryptor.swift */; }; + 6DA6EEC44EB98C02ED794A90A0AF255E /* NSImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 078B8292D545DFE2C5CD938BCB812BF2 /* NSImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6ECB086FCD9F99852D04EF7164799CAB /* SHA2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BCBF8BD04E98F16D5391D774A4D5C1 /* SHA2.swift */; }; + 6F1B74372FC3AA7C6C98671039F6BA49 /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 53C394B42B7968A28414E19226D7BFB1 /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 6F3D4FFD473B6D7EFE13688F9679E266 /* UIImage+MultiFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 492E42E49BAE2DDE8F7F547356939396 /* UIImage+MultiFormat.m */; }; + 6FE1DFD7DAEA3A28CE8195074D607724 /* Int+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F02C9C48A7A2C8407E3F514BCFD9335D /* Int+Extension.swift */; }; + 71B626C86FFD955C154A3BC3327215E3 /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D7D233D62F79E62FFA2EC91ACF06C04 /* SDWebImageCoderHelper.m */; }; + 73C444AF5780268AC3A7CBA1D9CB1245 /* TransformOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47CD592978CC4B92452ADA4ABBAB4803 /* TransformOperators.swift */; }; + 75BD6C90A7F4588FEA91C1C702D9A0C0 /* SHA3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 533C2539ADA8F13BB1BD294312BBB4AC /* SHA3.swift */; }; + 75DB763A45F389C7A22038E611D2DA85 /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A0C50437972D72F88FBD1569D9F259D /* Array+Extension.swift */; }; + 7738227A14449B8ED4758B8621F4BD28 /* UIImage+MemoryCacheCost.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F59BDCA3709C6225FE577FBFA09A656 /* UIImage+MemoryCacheCost.m */; }; + 777BFFAE705CE49B0B906D15FF00AC7C /* SDWebImageCodersManager.m in Sources */ = {isa = PBXBuildFile; fileRef = D1A15C0955F3655BC85CE5A74E77F47A /* SDWebImageCodersManager.m */; }; + 77A5A8CE350CAEA3C22B6AF11D049A57 /* Cryptors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E05B6BBEC2DFE3C8152FA0893EF346B /* Cryptors.swift */; }; + 7840564DDAB7AB3396808E321E51D882 /* SDWebImagePrefetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = CBD91AC822910EC52639A4A2C7358026 /* SDWebImagePrefetcher.m */; }; + 78B8F270B43ABF2D7BC5A7683A8A2AB8 /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 81B658E690B21A3A9E181A0ABB6E5E70 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7943B85076F29D747D2E499C2EE6A811 /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = F197377846D1C807408A25308E5E10AE /* SDWebImageTransition.m */; }; + 7ACCDEDD9521549FA41E0E172447D2F5 /* AlamofireObjectMapper-watchOS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 223513C72298BB481E8F1B33DC47C0F0 /* AlamofireObjectMapper-watchOS-dummy.m */; }; + 7BB18C59ABE36E32FFCCFC99CB0FD4FA /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EFA2D0F1DC58334781AF7D50B53FAC5 /* SDWebImageDownloader.m */; }; + 7C266B5B99C315500567C5E092B90833 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = 66E5B19A3447183BDDEBB8C3D231FE60 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7C62E119FC58DBE1655C2B09745837F5 /* TransformOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491E3482FFE9D75092E0FD00A4E2C144 /* TransformOf.swift */; }; + 7D2E607FB3630D77F3F0DB8CC3C99195 /* String+FoundationExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58706E4731DB31F7E51958134686A6EF /* String+FoundationExtension.swift */; }; + 7D66B93BAB2738CEB4FF21C160082B9B /* SDImageCacheConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A46A7D9CED5FA4156C5A1DE790FEC3C /* SDImageCacheConfig.m */; }; + 7ECE948FC4ECA85A3F8E865244225390 /* URLTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67340A7EFCE654D4C23EAF007F66C19E /* URLTransform.swift */; }; + 7F3CC364EE02234A5E36FAD7B3B413BF /* SHA3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 533C2539ADA8F13BB1BD294312BBB4AC /* SHA3.swift */; }; + 7FD7936CD655B149A2F525161A9F6E6D /* StreamEncryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D2FFE8BB73DE0387C92C95013346E7 /* StreamEncryptor.swift */; }; + 80DA6F9F783B2D77812FD51927CCB0A1 /* BlockModeOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C26871F2127DFE55454DFB49C28A3FF /* BlockModeOptions.swift */; }; + 81A2A8BB1E7BE4BE8EAA7AE4E2C7573F /* UInt64+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C8BB3749670E28B26AE6AD0F877E3BA /* UInt64+Extension.swift */; }; + 82BA89811E67B211A5BC1F2902F0A40F /* SDWebImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8EC1117E36EC72700C886B6C907A7408 /* SDWebImageManager.m */; }; + 82C72B35091073596FE61D069FFB8A80 /* Timeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0CC03C39DD572AE7054563A188AF245 /* Timeline.swift */; }; + 838BAC4654B08C65FCC286FC2E0061DA /* CodableTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D92F091DEF5B0921082C97AF24966C0 /* CodableTransform.swift */; }; + 84110DCD323D8B02BDD58AC4783A372E /* ObjectMapper-iOS-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = CA70E787EB2E6A5895307AAE2E288E68 /* ObjectMapper-iOS-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 843E862D6232E2617C20FE72CAFC28AB /* UIView+WebCacheOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 35D46D44A4A590E3E369C91F5AD26C87 /* UIView+WebCacheOperation.m */; }; + 845B829CF7011A308F9558751334CB9E /* SDWebImage-watchOS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 843717451DD664682B1546AE807018DB /* SDWebImage-watchOS-dummy.m */; }; + 84FB085C8CD5330D49B62BA15469712D /* SDWebImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 6EFA2D0F1DC58334781AF7D50B53FAC5 /* SDWebImageDownloader.m */; }; + 85248F7BF0AE3162DE7C37FBEACAA6D9 /* Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A280350348F5AB482446E0A01DE31E /* Padding.swift */; }; + 85C0440106C1A7A7DDB935EE24248EF7 /* SDImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 943077C55D579E24267EC6C5B0454DFD /* SDImageCache.m */; }; + 85E60A68EFBC58B96FAE3BAC44F578C4 /* ChaCha20+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23A0A9E23FB389361D3EFFD37AD3B744 /* ChaCha20+Foundation.swift */; }; + 864D17E2FE8121867019C30E59BE5E21 /* HKDF.swift in Sources */ = {isa = PBXBuildFile; fileRef = B488C5F5836A8E73CFC8CA67FDEF982D /* HKDF.swift */; }; + 86728D25113B805C9CB1679B7A5A1887 /* Rabbit+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C26BA20945990CC20CCBCC08FC64E1 /* Rabbit+Foundation.swift */; }; + 8B1E87732D0D5158122E5514CB8E6010 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = AA230FA10E148D436F0096A332E674F2 /* UIImage+GIF.m */; }; + 8E8CA6B26DE8101725A2CE5700E82A26 /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C36A385EA45E5291F09DB4C8396BC6F /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 8F5EA601325668BE77836C2E2491F5A5 /* SDWebImageCompat.h in Headers */ = {isa = PBXBuildFile; fileRef = 6609A66E0D47DCD51DB0589EA61119C3 /* SDWebImageCompat.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 903A7D735806F25CA810601309FF000E /* CMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B39E7D5BB0862C62CDC4FF1A2F399A1 /* CMAC.swift */; }; + 91052846D92E85DDAAD5CD2813507211 /* Data+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1999E800D436061AA2CD5555C6A4698D /* Data+Extension.swift */; }; + 912A476FD85EECC920A508E12460EFB8 /* Alamofire-iOS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = C6C3D9547308DB93D42D38DAC51DAF8A /* Alamofire-iOS-dummy.m */; }; + 91D45871DE32A3C1B2E845F54E9A2660 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3127E182056505DD5B33AD124A8F6B1 /* Request.swift */; }; + 92C3F61E498DE72314339CC891054DC4 /* Int+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F02C9C48A7A2C8407E3F514BCFD9335D /* Int+Extension.swift */; }; + 9360A96BD6459848ED6EF26D8DADFE5A /* NSDecimalNumberTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1D01AEBA8A6116CA91054054C4EC1E /* NSDecimalNumberTransform.swift */; }; + 940B03BF74329B97EAD34FE317F7F1F7 /* Rabbit+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12C26BA20945990CC20CCBCC08FC64E1 /* Rabbit+Foundation.swift */; }; + 94B030B37731DFF25193BE88E5A3C40D /* Checksum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCC8182E432EFE46A02256C7EB6D564 /* Checksum.swift */; }; + 952B55A2A89F29F246568BC14E5F7245 /* UIImage+MultiFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D817A21EC4523EBBBD1C2D8E17CED11 /* UIImage+MultiFormat.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 95924A7F08FFDA37D0E07330585B0F7C /* BlockMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4486FDC523F6036877D028ACC7575A91 /* BlockMode.swift */; }; + 95ACABC71585D657249CC92BA7731A8F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA160AA3138E9D4CCFBF58278868FD65 /* Foundation.framework */; }; + 96288FBB89EE8E87DE4AB79350B95D31 /* UIImage+GIF.h in Headers */ = {isa = PBXBuildFile; fileRef = 66E5B19A3447183BDDEBB8C3D231FE60 /* UIImage+GIF.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 968D99188F43BC53E16A9A4B8A0F2EDC /* UIView+WebCacheOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 81B658E690B21A3A9E181A0ABB6E5E70 /* UIView+WebCacheOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 97042F4038DDEB535F984C659D78D0BB /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38D2955A508F53B2621EC6165CA16ACC /* Utils.swift */; }; + 9710AA8455D26EB1E65EC48EB73662E5 /* TaskDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5058D4CAD4BA5182249468FCE66189B8 /* TaskDelegate.swift */; }; + 98A2AC4BCD9E2B757847828E9C5F1F82 /* Authenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E3924369A79764E740EEAC21ACEA21 /* Authenticator.swift */; }; + 98B68DD45987E99FB68542776889FC17 /* SDWebImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = D6509D88F413480F9B11247D7A31549A /* SDWebImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 98C94873E547AAD3BC4AA1F4D3EB2FF1 /* SDWebImageTransition.h in Headers */ = {isa = PBXBuildFile; fileRef = 914A98F250AD776F45A885D1B3D91DE0 /* SDWebImageTransition.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 98EB0914754838B056FC2410E28436A1 /* Validation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42505EEE9F52E1B31ED6A637B15D7383 /* Validation.swift */; }; + 9989104278D65E6AEF8BD0E65CC17251 /* NSImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C1A9A84A5151F6158459DBB5A1F72D5 /* NSImage+WebCache.m */; }; + 99C1A41C9D214EA1BE189149F0F53275 /* SDWebImageImageIOCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = E3D5C30DCE7867365039FD693D17E6D1 /* SDWebImageImageIOCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9A0D8180A8542BD19E2AEF533626FD32 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE4A55F1AB2AFA507296B580FEC587C /* Response.swift */; }; + 9A1DF7F0364E8E12E0C6D6CE25DBAD69 /* OFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE4572688292058D24E25808BFB7F214 /* OFB.swift */; }; + 9ABA6D814581D90649BB715E37C31758 /* Mappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2DE6CE475EA18FEECF0A57C67576A88 /* Mappable.swift */; }; + 9B809B1D23140B74109D2944D7B85370 /* AEAD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 31A0C06C72AC2BB4DA4355BAA129F8BF /* AEAD.swift */; }; + 9EAAF055B1642982B8904E7D72620DB0 /* PCBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE93082785221668B0DF44977020973C /* PCBC.swift */; }; + 9EE2A1ADB2CE1B2682639A9CC596F997 /* DataTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6B38173AAE3F4E4D4C374AA2AAF68276 /* DataTransform.swift */; }; + 9F587E6B4E3402F772D1520A97CB85F8 /* PCBC.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE93082785221668B0DF44977020973C /* PCBC.swift */; }; + A08F1D18CABBDCBE14D5BE2A7D352D24 /* ObjectMapper-watchOS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6708838356B19F3CE6CC1DB597AF05C0 /* ObjectMapper-watchOS-dummy.m */; }; + A0E1AFB4104DD8C24BA35979E670F51F /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE51F59AA1FB91C91AF5CCB03EF5BBB /* Notifications.swift */; }; + A10EE5EFCCDC8466FA0154AA9DFB3737 /* CipherModeWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 908B397C63C8C34F165CAD8E07B2B429 /* CipherModeWorker.swift */; }; + A1200D1514F89E19300D9F272856845E /* IntegerOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CDCE9F4E104ACC626EEEF1A601E4CD /* IntegerOperators.swift */; }; + A1BEDFE18055DC04EE59115BEB931F1E /* Data+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1999E800D436061AA2CD5555C6A4698D /* Data+Extension.swift */; }; + A2F83CDFEA624C6C57C527F9F378D19A /* MapError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87E6C9F2F10891B6C1D7116A2E3CD8B9 /* MapError.swift */; }; + A3007EA32DCAB1CA67795414671FF618 /* SessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C0E1D8BB5A80DEE7944B70EBD304267 /* SessionManager.swift */; }; + A477E26F53C09078BA003D36E997C151 /* ISO8601DateTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1D705189D79F699FF674088C380272 /* ISO8601DateTransform.swift */; }; + A4CAA381B50248056BDFB9AFBD8867C9 /* AFError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DF89231999CD17564BBD2E53963AE6E /* AFError.swift */; }; + A4F3413A8B6FD95BFB3C301CCB2FE7C3 /* Mappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F2DE6CE475EA18FEECF0A57C67576A88 /* Mappable.swift */; }; + A69DBD7FB7755B51EA36FC6D8BA12704 /* Authenticator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E3924369A79764E740EEAC21ACEA21 /* Authenticator.swift */; }; + A7439EE8D743922E845702130BE2541B /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAEBB50390AA61AD781599F0627E4C4B /* Operators.swift */; }; + A8C6E353DBCC0D1D34847D267AB7EF61 /* UIImage+GIF.m in Sources */ = {isa = PBXBuildFile; fileRef = AA230FA10E148D436F0096A332E674F2 /* UIImage+GIF.m */; }; + A9483F1921A4A994980A87F978BC7086 /* Scrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = F60A0F17365215CD2E821F7C5150FF7D /* Scrypt.swift */; }; + AA18263C63CD5F1F592297D6772E212E /* SDWebImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = BFBE462ECF236FE4293B18544541364A /* SDWebImageCoder.m */; }; + AB65FF8297EA4D6868602C0113CCA839 /* CTR.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B1C8CC6167248D84957B7ADA1E0244 /* CTR.swift */; }; + ABB633F1FA37ADCBFC48F2399B84EF60 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA160AA3138E9D4CCFBF58278868FD65 /* Foundation.framework */; }; + ABF48D749FC078372C89F3D6EE80A1DA /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D498EE4B8D4EAA6E7038D01E4D8EB88E /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + AC4A7F82DA71924C159A0F019EA6B14D /* Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47A280350348F5AB482446E0A01DE31E /* Padding.swift */; }; + AF205ABAAF2755544370C160DC8EC490 /* HMAC+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47841E0B2A196904B1250178233B0C29 /* HMAC+Foundation.swift */; }; + AF3BAC08E78954BD1E344D7E6A0C066F /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38D2955A508F53B2621EC6165CA16ACC /* Utils.swift */; }; + AFA9BCA194B0E1ABFDED55E02B3153F5 /* NetworkReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 154B32DDA57B67BB85BE4EDC9F94D237 /* NetworkReachabilityManager.swift */; }; + B172ED0AC453B91CDE97CD7EFAA5B143 /* SDImageCacheConfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 61CB331B8CD0303E2231784911D66A13 /* SDImageCacheConfig.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B1BF52B1EE2B1A9A0737B408C040DC50 /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = CC73C6B98C768EC395622233EB32D86F /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B2125307524BEAF53AC64600862ADF4C /* SDWebImageCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = BFBE462ECF236FE4293B18544541364A /* SDWebImageCoder.m */; }; + B3B70E729B9DBE6F4738BC9CFBDECD04 /* ECB.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA3483723D40955DEACECCC483FB9AC7 /* ECB.swift */; }; + B3D2380657D0565B887DBED07ABBE022 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA160AA3138E9D4CCFBF58278868FD65 /* Foundation.framework */; }; + B4475FE96A5EB06ABC96CEA377C62B0C /* Alamofire-watchOS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8633315FBBD3CD0F635B0D8D3F3AFD36 /* Alamofire-watchOS-dummy.m */; }; + B51460CAD56A2ECF0E246A5AD5F4D66D /* Blowfish.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC2A4E30DAEFFBE606F12B74951BDD8A /* Blowfish.swift */; }; + B5E09D67C012F834056AC332C7C30363 /* BatchedCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0312205F7DFEECFAA5D36AA6DB32459 /* BatchedCollection.swift */; }; + B60DDBD5F90AB17045F9A9CC4B24EEFB /* Digest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E7F57F121D9B91B455E018464D636FE /* Digest.swift */; }; + B64A4FB37BAF466D996B76B8636F9924 /* BlockCipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64D0E31F7478A5D3CC1E0F67F71531EE /* BlockCipher.swift */; }; + B6775198FDCC82EB570DDCED95B912A1 /* GCM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F1237FA10AC9A3ECB0203D8A4DF99A1 /* GCM.swift */; }; + B7BB5A1A61BA555178810C0A916B04BD /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C395ADF15FB8CC5203C1D322A051553 /* SDWebImageGIFCoder.m */; }; + B8B5DBE63811D7D77F500DB12838FFD8 /* ToJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41CE0E198552CF07557A00D4F80C0F36 /* ToJSON.swift */; }; + B96E48C00BD5DD0E42F7AC38903FC514 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = D34F2E10923BD125CC6DAA118EAA5435 /* NSData+ImageContentType.m */; }; + BA216F9064812FB41D691FC6F06EEBA8 /* CryptoSwift-iOS-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 46B8798D6E0EBDDD8226815DB42D53CA /* CryptoSwift-iOS-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BA9ED09E5C5C7485AC1A8573DAB5CE82 /* SDWebImageDownloaderOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 53C394B42B7968A28414E19226D7BFB1 /* SDWebImageDownloaderOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + BAEE814157F78C267981190CCCAE0AFE /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E163351D4E2C8D729AA52C9E28A394FE /* Foundation.framework */; }; + BBE2ABFFA12B206F9C07615EF7BAF6D0 /* CMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B39E7D5BB0862C62CDC4FF1A2F399A1 /* CMAC.swift */; }; + BC7C2C97510030284CF6E97FCBD45A35 /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 20645947CE2E4DF76C0C21F0A4CC470B /* UIImageView+HighlightedWebCache.m */; }; + BCA271D3F60C2BB48588E45A038ABABB /* NSDecimalNumberTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C1D01AEBA8A6116CA91054054C4EC1E /* NSDecimalNumberTransform.swift */; }; + BCE8F32EB03AFB8A28A6D42267C527BD /* EnumTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6FE948AF72E43DA87B86E6EE34844AA7 /* EnumTransform.swift */; }; + BD3C3F8B2BAB2D9D8613152D804CEAC9 /* DigestType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411016B0FBF632DC10A7F987F66E1CB /* DigestType.swift */; }; + C06D290B9216533843023A0BF93F5927 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E2D3E13915B9672343ACB9DE3D89DEC /* QuartzCore.framework */; }; + C23B248793952A4857145A3A869A68A9 /* UIView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = CC73C6B98C768EC395622233EB32D86F /* UIView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C41D774CB57D4E34CB54B69BA27CE44E /* SDWebImagePrefetcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C36A385EA45E5291F09DB4C8396BC6F /* SDWebImagePrefetcher.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C4DFB892A3B6CAB1BDFCF0C2D2BA3DE5 /* CCM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94B0295AEBC7F3211F22028415362C95 /* CCM.swift */; }; + C55991A2CFE9D69CCFAFAAB47481A583 /* Blowfish.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC2A4E30DAEFFBE606F12B74951BDD8A /* Blowfish.swift */; }; + C5672C4E73195617642F968F5775A50A /* TransformOf.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491E3482FFE9D75092E0FD00A4E2C144 /* TransformOf.swift */; }; + C581285B8AB6D47A2BBC0F1FB0436437 /* Alamofire-iOS-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = E55B679DF089154E9E3155339161B9C0 /* Alamofire-iOS-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C6347B8872EEC1A20EBA03B1C8CB4AE4 /* UIImage+MemoryCacheCost.m in Sources */ = {isa = PBXBuildFile; fileRef = 9F59BDCA3709C6225FE577FBFA09A656 /* UIImage+MemoryCacheCost.m */; }; + C6466A8C86E3207B73F20437B8E13999 /* CFB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 790FEA4A05DD92EE9916842AF2EDD8C3 /* CFB.swift */; }; + C671C085675E3F739DA0FFCB1C56E667 /* ImmutableMappable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47804D2377F9E25533891D9B9C72C58A /* ImmutableMappable.swift */; }; + C6B9E73B20C867D11C52F1FF43D1908B /* SessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FB7555B50165984CBBB4A22E2E1425 /* SessionDelegate.swift */; }; + C7ABC1A7419640A1072B50D86EA569A7 /* SDWebImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5A801FD7920FCF7B684C7A4BFAF63A /* SDWebImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C7DFBFA2EC8D8C2491FEE96F274F65DD /* Checksum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9CCC8182E432EFE46A02256C7EB6D564 /* Checksum.swift */; }; + C7E530B3A0405BD8B338F9D3DB0978C8 /* ParameterEncoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 245CFE0D7E98B32922BCC4E1D7A71809 /* ParameterEncoding.swift */; }; + C8C4339B907EE129905A88770D62E25F /* UInt16+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23CB7AD01B3AEF46B5390A8C2168CF21 /* UInt16+Extension.swift */; }; + C964F6A2C51B36C12124F2FC45A8F774 /* UIImageView+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 757FF0BF3BF390A8D5EA34773154614D /* UIImageView+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C9B7416EECE402B488F2FB80194D7E4A /* StreamDecryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773C7DCD3A6D2C43B7F7FEA7F3D4D25A /* StreamDecryptor.swift */; }; + CAE2DF120825C5A145C6C9BB7503A495 /* ZeroPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB0407015DEE2575F91C4C608D1B686D /* ZeroPadding.swift */; }; + CD1E6265FDE55BFF1CA691437CBF8398 /* NSButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DE20B76C04AA5CF2B9733747FA8611F /* NSButton+WebCache.m */; }; + CD215AE8FB5D1B3EF3D4B04AE47C0BF4 /* NSButton+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = B78C1CBD3175E21DEA630033F390D15B /* NSButton+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + CDBEF9271A3D4CAD33C10DFFEAE24431 /* Utils+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0DA179FAD7A331AED02CEE24C70925 /* Utils+Foundation.swift */; }; + CE31A8F48BCBF803CD4E141E6BDED9A4 /* NoPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B044125FB9727CC592AF1BFF2CC2F2 /* NoPadding.swift */; }; + CEA20537663F62BCEBEC9B6560A40796 /* UInt64+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C8BB3749670E28B26AE6AD0F877E3BA /* UInt64+Extension.swift */; }; + CFEF2C7F05632F2E54E2381DE8306D68 /* Pods-Watch Extension-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 820C57EB7696886472978F85CA00C503 /* Pods-Watch Extension-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D12F579CEE2B66C02EC6B6A5FDE38A81 /* Cipher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 397A89A1E00B8670B3F71320935E1342 /* Cipher.swift */; }; + D17C3FD8E125B305C71FE2DDF9177365 /* NSImage+WebCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 078B8292D545DFE2C5CD938BCB812BF2 /* NSImage+WebCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D18B66F656E0C735974BFDC5C56F5FD6 /* UIImageView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = F23837990984900FE72488992448FDAC /* UIImageView+WebCache.m */; }; + D41C1FFD88013EDE76C8DF9BCD1A241A /* SDWebImageCoderHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D7D233D62F79E62FFA2EC91ACF06C04 /* SDWebImageCoderHelper.m */; }; + D4840B434912B55E6AF0E57E006D5A77 /* UIButton+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF19C129E29A610DB4B377B99E06B9C /* UIButton+WebCache.m */; }; + D486967D802581AD706F178CFAB88147 /* Updatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9720BAAF7DC2D2F0AC082B1A100BC164 /* Updatable.swift */; }; + D5D647DB518CED93C4D5F0C262255E6B /* UInt8+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D25864C51D6CCE0C9E1EF1442594EEA /* UInt8+Extension.swift */; }; + D61632283DE47E05830AF9361BF9E178 /* FromJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D31C620E17F575E6E2F90BC9D2A29AC /* FromJSON.swift */; }; + D647AC1C09248E9D70678AD2C9AB7082 /* AlamofireObjectMapper-watchOS-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 7648D746B888CAE88B320285E4D3476C /* AlamofireObjectMapper-watchOS-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D80597936DA978F70A2E6D7EC71282B3 /* PBKDF2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 425747501EF0C921813B08642430C109 /* PBKDF2.swift */; }; + D9A3D5DE6A8CF2DD3EB35A030F200E5E /* UIView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = E2C55A5F184670CD2D61B8ACC7D22EA7 /* UIView+WebCache.m */; }; + DA0C259DA7E7D1791A93FA61BD6EB1EB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E163351D4E2C8D729AA52C9E28A394FE /* Foundation.framework */; }; + DBD47EC2D2068A32564D6BD2C2B20221 /* AES+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C15A47D715F6B15E5149A633B9C36EFE /* AES+Foundation.swift */; }; + DBE9B8656C8F9F173B4FDDDB63CBF2EF /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = 799EBBE8EA9380002541B3BDC2509DFA /* Operators.swift */; }; + DD2E2CD6C02C74685463B15F71AA38E3 /* PKCS5.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCDF52BDB380C340B3D3DAE01DF1FD66 /* PKCS5.swift */; }; + DD30892CAFD4402BD8E2282DC1EE3877 /* SDWebImageTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = F197377846D1C807408A25308E5E10AE /* SDWebImageTransition.m */; }; + DD50BC31EFA8E65EC871E8AC986E037F /* SDWebImageGIFCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C395ADF15FB8CC5203C1D322A051553 /* SDWebImageGIFCoder.m */; }; + DD50DC39177440B69D76CE063CA3AC87 /* AlamofireObjectMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 697F8F18238B03CD61C66E641D381323 /* AlamofireObjectMapper.swift */; }; + DEC1CD260AED653C6C70863D47680E0B /* HMAC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CA2EE4ABF8769574D46F419F7513E7D /* HMAC.swift */; }; + DF47FAC7F3F8A969D9F9EE47410E1B93 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E163351D4E2C8D729AA52C9E28A394FE /* Foundation.framework */; }; + DF9E902055B942E440A600199F26C71D /* CodableTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D92F091DEF5B0921082C97AF24966C0 /* CodableTransform.swift */; }; + E034E406CEA11CB9D4D3DCE9400EF957 /* SDWebImageCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D502B6FDF14EB7F9077C2048BB9117F /* SDWebImageCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E079A0DB030F050D9E1EC03B9B2585AC /* SHA1.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8C5C58AD00C41F3B2BAE57C718CE33D /* SHA1.swift */; }; + E0DF3A0ED5FAA2FE0C1E2396CBC4F968 /* MultipartFormData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4136293AF5C2A5645461EBE3091D1C6 /* MultipartFormData.swift */; }; + E0FDBFAC8A133626CDCEF45E0F620FBA /* SDWebImageImageIOCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2762DCE84D02C12B44357EF970B68C /* SDWebImageImageIOCoder.m */; }; + E1803407BAA1F6EAA46DB10B3D9AE6BB /* AES.Cryptors.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFDE164DAA6A067E81B4D6E89B59850E /* AES.Cryptors.swift */; }; + E2F9BFECBBEBDF515A49318C8AF36D74 /* NetworkReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 154B32DDA57B67BB85BE4EDC9F94D237 /* NetworkReachabilityManager.swift */; }; + E372E2A2A5FD43A01E4D3059AEF97F9C /* CryptoSwift-watchOS-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = F4D5CF5092130A6E395AF669B51A2C1A /* CryptoSwift-watchOS-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E3C0F0871B18438048CE5C9C51F71E35 /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = A0A53F4EDA002C9FBBE33208D441E01F /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E4887126524555D98F7C26807C8C872D /* Blowfish+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28C3BC66B278570FFDEE73352885A4CC /* Blowfish+Foundation.swift */; }; + E4DCB1B21E77C670085A051143CD9E66 /* SDWebImageOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = A0A53F4EDA002C9FBBE33208D441E01F /* SDWebImageOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E58AFF30DC5FB85967E17B104B7C436F /* ChaCha20+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23A0A9E23FB389361D3EFFD37AD3B744 /* ChaCha20+Foundation.swift */; }; + E7172B475D62C28BEF8E044C7243D65D /* SDWebImage-iOS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = A0AC9DD97964FA91D93CA6221978608D /* SDWebImage-iOS-dummy.m */; }; + E817D6A4B21742A4AB91330BC605A53B /* SDWebImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D498EE4B8D4EAA6E7038D01E4D8EB88E /* SDWebImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E8AAD097E6F3BD0C9B8A13B63D402493 /* SDWebImageFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 89F55E53A7E33823B2E6DD656AE2D71F /* SDWebImageFrame.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E8E65396A4375B8F50714A5BE658E557 /* ObjectMapper-watchOS-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 1428B300F5C24951DC479A75C343EA14 /* ObjectMapper-watchOS-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E9478B9C29741BB15C26529B33AD798D /* ResponseSerialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33941F96D2513278A5F2225BC00F4B18 /* ResponseSerialization.swift */; }; + EA1EAB31972EC3579B31C8A7083351D9 /* AES.Cryptors.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFDE164DAA6A067E81B4D6E89B59850E /* AES.Cryptors.swift */; }; + EA2DA37B7ED37959847875D89F6D3271 /* Timeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0CC03C39DD572AE7054563A188AF245 /* Timeline.swift */; }; + EC6F596A19B56DB0470BFEDC6445F224 /* DateTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D15C250294C4B5E1EE5502CD51CD0B3 /* DateTransform.swift */; }; + EE217BC1DA5EDDDC645CF1CA2E532EE6 /* Array+Foundation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C66354493DBECB5149CAB1B8BAE892E /* Array+Foundation.swift */; }; + EE45C83BE8BEE144D0FDE1C4C552E12A /* SDWebImageGIFCoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B5A801FD7920FCF7B684C7A4BFAF63A /* SDWebImageGIFCoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EE822282C912F20733663B0E9FAEAD6B /* ServerTrustPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0F4A73853B69418C200A0180A7FC4DB /* ServerTrustPolicy.swift */; }; + EEF53A9F65D755A52D2CFDC8ED1058B3 /* SDWebImage-iOS-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 40F50335C7F937505F15341FD4ADA2B5 /* SDWebImage-iOS-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; }; + EFBEBAF457182E041C47739505468482 /* ISO8601DateTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1D705189D79F699FF674088C380272 /* ISO8601DateTransform.swift */; }; + F02FC1BB9AE21AB8A44ED989820240B1 /* CCM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94B0295AEBC7F3211F22028415362C95 /* CCM.swift */; }; + F0B6D1AF9B9BD8DE4403C30A9A93E5DE /* UIImageView+HighlightedWebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 20645947CE2E4DF76C0C21F0A4CC470B /* UIImageView+HighlightedWebCache.m */; }; + F197A795CA0D500CCA5351183EDAF6BD /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472B024F353D47204165DCAEAF286DCF /* Result.swift */; }; + F1DB4730A8DE6E59EED9E2B60F3F1EC8 /* SDWebImageCoderHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 378FDDCE9E13EB010D91074AB4C18BF5 /* SDWebImageCoderHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F20DC2AD815B177396D8BB45C3888751 /* DigestType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8411016B0FBF632DC10A7F987F66E1CB /* DigestType.swift */; }; + F2884C16786810D1B40F39DAFBCF4303 /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE51F59AA1FB91C91AF5CCB03EF5BBB /* Notifications.swift */; }; + F31AFD9C51489632A37CEA5705D55BE6 /* AlamofireObjectMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 697F8F18238B03CD61C66E641D381323 /* AlamofireObjectMapper.swift */; }; + F407208CBBF05D9333102FAF0480F31F /* Mapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8548C09A1A91E9A78E396912E7341AC /* Mapper.swift */; }; + F4A127D0320C2D561CE43ADC6BEAFB73 /* Generics.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF8325A35C0DCE5CBE4E54CB9076259 /* Generics.swift */; }; + F5202BB39510DE07DEB984BA640F2008 /* UIImage+MemoryCacheCost.h in Headers */ = {isa = PBXBuildFile; fileRef = 8AEC4674D34D88026D83CC62A515512B /* UIImage+MemoryCacheCost.h */; settings = {ATTRIBUTES = (Public, ); }; }; + F521AAF77D40DBF1080A4D020D8AA436 /* Cryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24C0980CBE1EFBEF2247F08C12724914 /* Cryptor.swift */; }; + F583AEF68EAC42313F3CDDAE6AACA9FF /* SDWebImageCompat.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DB9CD2F0897EAF9893BF859B2D73C22 /* SDWebImageCompat.m */; }; + F65EF8AB866F591B590E768F116A4A6E /* EnumOperators.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6016CF43C0B2D31043ADD65889FBB42 /* EnumOperators.swift */; }; + F78C24389C713F356E0494546F7751F2 /* Rabbit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3B80E4AF948917D76BC73171318A007 /* Rabbit.swift */; }; + F793BF43B1DC4C85E6DF77DB25165BC8 /* BlockDecryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4887F39F9288BCE0542FEDF35B09ACB3 /* BlockDecryptor.swift */; }; + F794078DB0BFC4ECA72352AAF90EFE4A /* Scrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = F60A0F17365215CD2E821F7C5150FF7D /* Scrypt.swift */; }; + F9B5B9564F737D9B8577DFC6E471FE68 /* PKCS7.swift in Sources */ = {isa = PBXBuildFile; fileRef = 446A03A259525DA90A1935D4F9C81A9C /* PKCS7.swift */; }; + F9D1748CA6F11992315C2532934EE4BC /* MD5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C1556FAF37B97DFB2249475C26CAB5 /* MD5.swift */; }; + FB967296A5EF6F11F3C80E0579A4FF2C /* SDWebImageDownloaderOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 53CD26E0EC964DBCE766401B9E13A32F /* SDWebImageDownloaderOperation.m */; }; + FBBB16BB9F3574C263332B3D6ABED1A7 /* SDImageCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E576DE9C1B8474304A4A7807AE657421 /* SDImageCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + FC323405C3A2FCC9514FC8A68CEF8580 /* AlamofireObjectMapper-iOS-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D19F4243CB2ED9AEDBC8118906A92318 /* AlamofireObjectMapper-iOS-dummy.m */; }; + FC6BB17D15EC8A4D2134D858B3A7F415 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E163351D4E2C8D729AA52C9E28A394FE /* Foundation.framework */; }; + FD64536EC4128B709C73E634866C7987 /* PKCS7Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 205B852C5AEA3938C4D0682669465ABC /* PKCS7Padding.swift */; }; + FF0835B3ECDED1DE76455DE10A228B58 /* DispatchQueue+Alamofire.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F2BF12B2417E7E9CA801120E04FB7E /* DispatchQueue+Alamofire.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 124EE9D94BF992283F49103CBB9EC1C5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D01A02B225FD29F76E911D60DBFD443C; + remoteInfo = "ObjectMapper-iOS"; + }; + 1447A4A082CA04D2ACA478851CC4AADE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FD8828BFC368157226E204A32CD5B6DE; + remoteInfo = "Alamofire-iOS"; + }; + 23682F5127A4EF0AEAC9B59E3DF7CE2E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D01A02B225FD29F76E911D60DBFD443C; + remoteInfo = "ObjectMapper-iOS"; + }; + 3C8E35F0422AB550C6F1D3FE2FF8AC3E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 744F52F389060600FE79F1B9A709C630; + remoteInfo = "SDWebImage-iOS"; + }; + 4FA4D2B70C3DED3901BB28F4E4653533 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 6447A5D6B2905FE6A09B0ABC0042EC50; + remoteInfo = "SDWebImage-watchOS"; + }; + 63C69FAE89ADC8A2AEB89D90F547EF56 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 66F51BC925FD5FB829E8D422C690BDF0; + remoteInfo = "Alamofire-watchOS"; + }; + 6597C94C9047056BD950B5D106680791 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 7B450F2E8D53215597AEE594BA0BB14B; + remoteInfo = "AlamofireObjectMapper-iOS"; + }; + 8533914E134A5C153EA97FF41FA205AE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = FD8828BFC368157226E204A32CD5B6DE; + remoteInfo = "Alamofire-iOS"; + }; + 8AF4C5A939DC7945A7CFABDEEB8852E4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 66F51BC925FD5FB829E8D422C690BDF0; + remoteInfo = "Alamofire-watchOS"; + }; + A75EF66A4345AFDA41E7F6D19DD81BF1 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 77F4321EB2A71321DE0D59BDF4C62E3F; + remoteInfo = "ObjectMapper-watchOS"; + }; + B230A7274FDE0922425A9C41E261F5A0 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2FD806DB695223C0672239A9FE30B913; + remoteInfo = "CryptoSwift-watchOS"; + }; + BF57240D2D33AE990266C4D0E1832B7A /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B990BD87169C76A3ED3FE8A9258D91A3; + remoteInfo = "Toast-Swift"; + }; + C26F605802FB1E6E3F0A5F827E2A9577 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 77F4321EB2A71321DE0D59BDF4C62E3F; + remoteInfo = "ObjectMapper-watchOS"; + }; + E5D5321B1256D957685B195DBB384219 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 739D23BF96457378860369EA2DA315C9; + remoteInfo = "AlamofireObjectMapper-watchOS"; + }; + F353203ADC2154712A4E986A2F529989 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 218BFCBCA0EA83AEA95CE87303914A04; + remoteInfo = "CryptoSwift-iOS"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 00BE49C726548FF41D71F0AD2F2624B6 /* UIImageView+HighlightedWebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImageView+HighlightedWebCache.h"; path = "SDWebImage/UIImageView+HighlightedWebCache.h"; sourceTree = ""; }; + 01CB31E026580CB87518E18B1B4E832D /* AlamofireObjectMapper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AlamofireObjectMapper.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 01EC8D9B4A54CA713CAB406F17C2E5D2 /* Pods_BSRadioWaves.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_BSRadioWaves.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 028CE532624E25B101754545D1387E07 /* Toast.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Toast.swift; path = Toast/Toast.swift; sourceTree = ""; }; + 06D8CFEF1266346B6B82C5B7AAF6FD89 /* AlamofireObjectMapper-iOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "AlamofireObjectMapper-iOS.modulemap"; sourceTree = ""; }; + 078B8292D545DFE2C5CD938BCB812BF2 /* NSImage+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSImage+WebCache.h"; path = "SDWebImage/NSImage+WebCache.h"; sourceTree = ""; }; + 08F45D8ABEEC2A98771C4E897DAFC6A4 /* CBC.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CBC.swift; path = Sources/CryptoSwift/BlockMode/CBC.swift; sourceTree = ""; }; + 09C1556FAF37B97DFB2249475C26CAB5 /* MD5.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MD5.swift; path = Sources/CryptoSwift/MD5.swift; sourceTree = ""; }; + 0B5A801FD7920FCF7B684C7A4BFAF63A /* SDWebImageGIFCoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageGIFCoder.h; path = SDWebImage/SDWebImageGIFCoder.h; sourceTree = ""; }; + 0CF19C129E29A610DB4B377B99E06B9C /* UIButton+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIButton+WebCache.m"; path = "SDWebImage/UIButton+WebCache.m"; sourceTree = ""; }; + 0D082F4E7BF859609078D00BDE67D297 /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F4663658088190E2706E86A72103A64 /* SDWebImageFrame.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageFrame.m; path = SDWebImage/SDWebImageFrame.m; sourceTree = ""; }; + 12181444875E1B28643E159F03510953 /* SDWebImage-iOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "SDWebImage-iOS.modulemap"; sourceTree = ""; }; + 12C26BA20945990CC20CCBCC08FC64E1 /* Rabbit+Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Rabbit+Foundation.swift"; path = "Sources/CryptoSwift/Foundation/Rabbit+Foundation.swift"; sourceTree = ""; }; + 1428B300F5C24951DC479A75C343EA14 /* ObjectMapper-watchOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "ObjectMapper-watchOS-umbrella.h"; path = "../ObjectMapper-watchOS/ObjectMapper-watchOS-umbrella.h"; sourceTree = ""; }; + 145A91E809AD1CE2702E3F4069A17127 /* ObjectMapper-iOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "ObjectMapper-iOS-dummy.m"; sourceTree = ""; }; + 14F4FD10BB7A334B3B52ED6E3664ECC3 /* CryptoSwift-watchOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "CryptoSwift-watchOS-dummy.m"; path = "../CryptoSwift-watchOS/CryptoSwift-watchOS-dummy.m"; sourceTree = ""; }; + 154B32DDA57B67BB85BE4EDC9F94D237 /* NetworkReachabilityManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NetworkReachabilityManager.swift; path = Source/NetworkReachabilityManager.swift; sourceTree = ""; }; + 1664B5B9254FBFC12EFAD7F013FE6970 /* UIImage+ForceDecode.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+ForceDecode.h"; path = "SDWebImage/UIImage+ForceDecode.h"; sourceTree = ""; }; + 17CAAB77FCDE6347454F7A923FD58ACE /* SDWebImage-iOS.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "SDWebImage-iOS.xcconfig"; sourceTree = ""; }; + 18FB7555B50165984CBBB4A22E2E1425 /* SessionDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SessionDelegate.swift; path = Source/SessionDelegate.swift; sourceTree = ""; }; + 1999E800D436061AA2CD5555C6A4698D /* Data+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Data+Extension.swift"; path = "Sources/CryptoSwift/Foundation/Data+Extension.swift"; sourceTree = ""; }; + 1B6F47AD390E6C7ABB618D40AFCECBE0 /* CBCMAC.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CBCMAC.swift; path = Sources/CryptoSwift/CBCMAC.swift; sourceTree = ""; }; + 1C0E1D8BB5A80DEE7944B70EBD304267 /* SessionManager.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SessionManager.swift; path = Source/SessionManager.swift; sourceTree = ""; }; + 1E7F57F121D9B91B455E018464D636FE /* Digest.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Digest.swift; path = Sources/CryptoSwift/Digest.swift; sourceTree = ""; }; + 1F4753D1AB10D773CEF9839DE1B95FF4 /* Pods-Watch Extension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Watch Extension.release.xcconfig"; sourceTree = ""; }; + 205B852C5AEA3938C4D0682669465ABC /* PKCS7Padding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PKCS7Padding.swift; path = Sources/CryptoSwift/PKCS/PKCS7Padding.swift; sourceTree = ""; }; + 20645947CE2E4DF76C0C21F0A4CC470B /* UIImageView+HighlightedWebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+HighlightedWebCache.m"; path = "SDWebImage/UIImageView+HighlightedWebCache.m"; sourceTree = ""; }; + 21FBF47F8C9900718A5776DB63DBF696 /* CryptoSwift-iOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "CryptoSwift-iOS-dummy.m"; sourceTree = ""; }; + 223513C72298BB481E8F1B33DC47C0F0 /* AlamofireObjectMapper-watchOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "AlamofireObjectMapper-watchOS-dummy.m"; path = "../AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-dummy.m"; sourceTree = ""; }; + 23A0A9E23FB389361D3EFFD37AD3B744 /* ChaCha20+Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ChaCha20+Foundation.swift"; path = "Sources/CryptoSwift/Foundation/ChaCha20+Foundation.swift"; sourceTree = ""; }; + 23C0C5B89A668B8EB9F7A5DDF4DF9C5B /* Toast-Swift-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Toast-Swift-Info.plist"; sourceTree = ""; }; + 23CB7AD01B3AEF46B5390A8C2168CF21 /* UInt16+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UInt16+Extension.swift"; path = "Sources/CryptoSwift/UInt16+Extension.swift"; sourceTree = ""; }; + 245CFE0D7E98B32922BCC4E1D7A71809 /* ParameterEncoding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ParameterEncoding.swift; path = Source/ParameterEncoding.swift; sourceTree = ""; }; + 2491F1715A5D6D43C0B16A1F5DAEB741 /* Pods-BSRadioWaves-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-BSRadioWaves-Info.plist"; sourceTree = ""; }; + 24C0980CBE1EFBEF2247F08C12724914 /* Cryptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cryptor.swift; path = Sources/CryptoSwift/Cryptor.swift; sourceTree = ""; }; + 24E3924369A79764E740EEAC21ACEA21 /* Authenticator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Authenticator.swift; path = Sources/CryptoSwift/Authenticator.swift; sourceTree = ""; }; + 28C3BC66B278570FFDEE73352885A4CC /* Blowfish+Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Blowfish+Foundation.swift"; path = "Sources/CryptoSwift/Foundation/Blowfish+Foundation.swift"; sourceTree = ""; }; + 29F95D207B77C866435357C8CCAB387B /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2B3248A4BA39C7307B86266A2A7881B5 /* SDWebImage-watchOS.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "SDWebImage-watchOS.xcconfig"; path = "../SDWebImage-watchOS/SDWebImage-watchOS.xcconfig"; sourceTree = ""; }; + 2B55C727541578F1150E77E912FFEDE6 /* Pods-Watch Extension-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-Watch Extension-acknowledgements.markdown"; sourceTree = ""; }; + 2C26871F2127DFE55454DFB49C28A3FF /* BlockModeOptions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BlockModeOptions.swift; path = Sources/CryptoSwift/BlockMode/BlockModeOptions.swift; sourceTree = ""; }; + 2D558011831313537E5FB9AAE0D11C1C /* Pods-BSRadioWaves-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-BSRadioWaves-frameworks.sh"; sourceTree = ""; }; + 2F70ADFE3EBB5F53FFB56FC28B5EE670 /* SDWebImage-watchOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; name = "SDWebImage-watchOS.modulemap"; path = "../SDWebImage-watchOS/SDWebImage-watchOS.modulemap"; sourceTree = ""; }; + 30CAAA388CF42B22A57E09222AB587F3 /* Pods-BSRadioWaves.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-BSRadioWaves.debug.xcconfig"; sourceTree = ""; }; + 3126072088DB1957115ADAAEB4BEA52D /* AlamofireObjectMapper-iOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "AlamofireObjectMapper-iOS-prefix.pch"; sourceTree = ""; }; + 31A0C06C72AC2BB4DA4355BAA129F8BF /* AEAD.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AEAD.swift; path = Sources/CryptoSwift/AEAD/AEAD.swift; sourceTree = ""; }; + 33941F96D2513278A5F2225BC00F4B18 /* ResponseSerialization.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ResponseSerialization.swift; path = Source/ResponseSerialization.swift; sourceTree = ""; }; + 347776958F66D7BED07270422D442946 /* Alamofire-watchOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "Alamofire-watchOS-prefix.pch"; path = "../Alamofire-watchOS/Alamofire-watchOS-prefix.pch"; sourceTree = ""; }; + 34BCBF8BD04E98F16D5391D774A4D5C1 /* SHA2.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SHA2.swift; path = Sources/CryptoSwift/SHA2.swift; sourceTree = ""; }; + 35D46D44A4A590E3E369C91F5AD26C87 /* UIView+WebCacheOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCacheOperation.m"; path = "SDWebImage/UIView+WebCacheOperation.m"; sourceTree = ""; }; + 378FDDCE9E13EB010D91074AB4C18BF5 /* SDWebImageCoderHelper.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageCoderHelper.h; path = SDWebImage/SDWebImageCoderHelper.h; sourceTree = ""; }; + 381AD64BFD13490931D50993631E4947 /* Alamofire-iOS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Alamofire-iOS-Info.plist"; sourceTree = ""; }; + 389F6AE412BA3442C610F7AE0823BE3D /* SDAnimatedImageRep.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDAnimatedImageRep.h; path = SDWebImage/SDAnimatedImageRep.h; sourceTree = ""; }; + 38D2955A508F53B2621EC6165CA16ACC /* Utils.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Utils.swift; path = Sources/CryptoSwift/Utils.swift; sourceTree = ""; }; + 397A89A1E00B8670B3F71320935E1342 /* Cipher.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cipher.swift; path = Sources/CryptoSwift/Cipher.swift; sourceTree = ""; }; + 3B1A445A57C6FE99F504F8D345940BEA /* ObjectMapper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ObjectMapper.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3C1D01AEBA8A6116CA91054054C4EC1E /* NSDecimalNumberTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NSDecimalNumberTransform.swift; path = Sources/NSDecimalNumberTransform.swift; sourceTree = ""; }; + 3C66354493DBECB5149CAB1B8BAE892E /* Array+Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Array+Foundation.swift"; path = "Sources/CryptoSwift/Foundation/Array+Foundation.swift"; sourceTree = ""; }; + 3CA27772B0C1545A46B4A7DD89A4C8C8 /* Alamofire-iOS.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Alamofire-iOS.xcconfig"; sourceTree = ""; }; + 3D25864C51D6CCE0C9E1EF1442594EEA /* UInt8+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UInt8+Extension.swift"; path = "Sources/CryptoSwift/UInt8+Extension.swift"; sourceTree = ""; }; + 3D502B6FDF14EB7F9077C2048BB9117F /* SDWebImageCoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageCoder.h; path = SDWebImage/SDWebImageCoder.h; sourceTree = ""; }; + 3DC963D960B085F1307DF22177EBE772 /* Alamofire-watchOS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Alamofire-watchOS-Info.plist"; path = "../Alamofire-watchOS/Alamofire-watchOS-Info.plist"; sourceTree = ""; }; + 3E40BD236BFB5823682FB0FE1E7E15BD /* Map.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Map.swift; path = Sources/Map.swift; sourceTree = ""; }; + 3F662A585BB28AE3557F5C0968A8144A /* BlockEncryptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BlockEncryptor.swift; path = Sources/CryptoSwift/BlockEncryptor.swift; sourceTree = ""; }; + 400AB493334D2934D760FC53237DF7C6 /* ObjectMapper-watchOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "ObjectMapper-watchOS-prefix.pch"; path = "../ObjectMapper-watchOS/ObjectMapper-watchOS-prefix.pch"; sourceTree = ""; }; + 40F50335C7F937505F15341FD4ADA2B5 /* SDWebImage-iOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SDWebImage-iOS-umbrella.h"; sourceTree = ""; }; + 41CE0E198552CF07557A00D4F80C0F36 /* ToJSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ToJSON.swift; path = Sources/ToJSON.swift; sourceTree = ""; }; + 422CC1C0934FE7FC948E3569428B35ED /* PBKDF1.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PBKDF1.swift; path = Sources/CryptoSwift/PKCS/PBKDF1.swift; sourceTree = ""; }; + 42505EEE9F52E1B31ED6A637B15D7383 /* Validation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Validation.swift; path = Source/Validation.swift; sourceTree = ""; }; + 425747501EF0C921813B08642430C109 /* PBKDF2.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PBKDF2.swift; path = Sources/CryptoSwift/PKCS/PBKDF2.swift; sourceTree = ""; }; + 42F09DC6B1358D384F6F21CCC835E790 /* Alamofire-watchOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; name = "Alamofire-watchOS.modulemap"; path = "../Alamofire-watchOS/Alamofire-watchOS.modulemap"; sourceTree = ""; }; + 43DA6DFAA898F949ACBD91D709EF13F8 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 43FB744D3A7CA2381CF940DFC5A5FD7F /* SDWebImage-watchOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "SDWebImage-watchOS-umbrella.h"; path = "../SDWebImage-watchOS/SDWebImage-watchOS-umbrella.h"; sourceTree = ""; }; + 446A03A259525DA90A1935D4F9C81A9C /* PKCS7.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PKCS7.swift; path = Sources/CryptoSwift/PKCS/PKCS7.swift; sourceTree = ""; }; + 4486FDC523F6036877D028ACC7575A91 /* BlockMode.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BlockMode.swift; path = Sources/CryptoSwift/BlockMode/BlockMode.swift; sourceTree = ""; }; + 46381330451AB4591A668E6370CE74AB /* CryptoSwift-watchOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; name = "CryptoSwift-watchOS.modulemap"; path = "../CryptoSwift-watchOS/CryptoSwift-watchOS.modulemap"; sourceTree = ""; }; + 46B8798D6E0EBDDD8226815DB42D53CA /* CryptoSwift-iOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "CryptoSwift-iOS-umbrella.h"; sourceTree = ""; }; + 472B024F353D47204165DCAEAF286DCF /* Result.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Result.swift; path = Source/Result.swift; sourceTree = ""; }; + 47804D2377F9E25533891D9B9C72C58A /* ImmutableMappable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImmutableMappable.swift; path = Sources/ImmutableMappable.swift; sourceTree = ""; }; + 47841E0B2A196904B1250178233B0C29 /* HMAC+Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "HMAC+Foundation.swift"; path = "Sources/CryptoSwift/Foundation/HMAC+Foundation.swift"; sourceTree = ""; }; + 47A280350348F5AB482446E0A01DE31E /* Padding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Padding.swift; path = Sources/CryptoSwift/Padding.swift; sourceTree = ""; }; + 47CD592978CC4B92452ADA4ABBAB4803 /* TransformOperators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TransformOperators.swift; path = Sources/TransformOperators.swift; sourceTree = ""; }; + 4887F39F9288BCE0542FEDF35B09ACB3 /* BlockDecryptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BlockDecryptor.swift; path = Sources/CryptoSwift/BlockDecryptor.swift; sourceTree = ""; }; + 491E3482FFE9D75092E0FD00A4E2C144 /* TransformOf.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TransformOf.swift; path = Sources/TransformOf.swift; sourceTree = ""; }; + 492E42E49BAE2DDE8F7F547356939396 /* UIImage+MultiFormat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+MultiFormat.m"; path = "SDWebImage/UIImage+MultiFormat.m"; sourceTree = ""; }; + 4BB746D5F5ED9B9B024F39461D914A43 /* Alamofire-watchOS.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Alamofire-watchOS.xcconfig"; path = "../Alamofire-watchOS/Alamofire-watchOS.xcconfig"; sourceTree = ""; }; + 4BE51F59AA1FB91C91AF5CCB03EF5BBB /* Notifications.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Notifications.swift; path = Source/Notifications.swift; sourceTree = ""; }; + 4C36A385EA45E5291F09DB4C8396BC6F /* SDWebImagePrefetcher.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImagePrefetcher.h; path = SDWebImage/SDWebImagePrefetcher.h; sourceTree = ""; }; + 4D817A21EC4523EBBBD1C2D8E17CED11 /* UIImage+MultiFormat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+MultiFormat.h"; path = "SDWebImage/UIImage+MultiFormat.h"; sourceTree = ""; }; + 4D92F091DEF5B0921082C97AF24966C0 /* CodableTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CodableTransform.swift; path = Sources/CodableTransform.swift; sourceTree = ""; }; + 4E05B6BBEC2DFE3C8152FA0893EF346B /* Cryptors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Cryptors.swift; path = Sources/CryptoSwift/Cryptors.swift; sourceTree = ""; }; + 4E1D705189D79F699FF674088C380272 /* ISO8601DateTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ISO8601DateTransform.swift; path = Sources/ISO8601DateTransform.swift; sourceTree = ""; }; + 4E2D3E13915B9672343ACB9DE3D89DEC /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; }; + 4EA2B9E7598C53E3DB0F929D091814F0 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS5.2.sdk/System/Library/Frameworks/ImageIO.framework; sourceTree = DEVELOPER_DIR; }; + 5058D4CAD4BA5182249468FCE66189B8 /* TaskDelegate.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TaskDelegate.swift; path = Source/TaskDelegate.swift; sourceTree = ""; }; + 5149F2ED76FF28D39794B30B6B89D8E4 /* CryptoSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CryptoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 525C256AAFECE92A936CF2F90CD41B14 /* DictionaryTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DictionaryTransform.swift; path = Sources/DictionaryTransform.swift; sourceTree = ""; }; + 53094347E1ABA3120D3AD1AA9180D872 /* UInt128.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = UInt128.swift; path = Sources/CryptoSwift/UInt128.swift; sourceTree = ""; }; + 533C2539ADA8F13BB1BD294312BBB4AC /* SHA3.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SHA3.swift; path = Sources/CryptoSwift/SHA3.swift; sourceTree = ""; }; + 53C394B42B7968A28414E19226D7BFB1 /* SDWebImageDownloaderOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloaderOperation.h; path = SDWebImage/SDWebImageDownloaderOperation.h; sourceTree = ""; }; + 53CD26E0EC964DBCE766401B9E13A32F /* SDWebImageDownloaderOperation.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloaderOperation.m; path = SDWebImage/SDWebImageDownloaderOperation.m; sourceTree = ""; }; + 54A29DBE2CDA7892674DD31F6E993B72 /* Pods-BSRadioWaves-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-BSRadioWaves-acknowledgements.plist"; sourceTree = ""; }; + 56E95B11A8DE03F6CA005AD960DC0E2B /* ObjectMapper-iOS.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "ObjectMapper-iOS.xcconfig"; sourceTree = ""; }; + 58706E4731DB31F7E51958134686A6EF /* String+FoundationExtension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "String+FoundationExtension.swift"; path = "Sources/CryptoSwift/Foundation/String+FoundationExtension.swift"; sourceTree = ""; }; + 5DB9CD2F0897EAF9893BF859B2D73C22 /* SDWebImageCompat.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageCompat.m; path = SDWebImage/SDWebImageCompat.m; sourceTree = ""; }; + 61CB331B8CD0303E2231784911D66A13 /* SDImageCacheConfig.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDImageCacheConfig.h; path = SDWebImage/SDImageCacheConfig.h; sourceTree = ""; }; + 64D0E31F7478A5D3CC1E0F67F71531EE /* BlockCipher.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BlockCipher.swift; path = Sources/CryptoSwift/BlockCipher.swift; sourceTree = ""; }; + 6551AC70A6402369433BA24C84E9A435 /* SDWebImageCodersManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageCodersManager.h; path = SDWebImage/SDWebImageCodersManager.h; sourceTree = ""; }; + 6609A66E0D47DCD51DB0589EA61119C3 /* SDWebImageCompat.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageCompat.h; path = SDWebImage/SDWebImageCompat.h; sourceTree = ""; }; + 66E5B19A3447183BDDEBB8C3D231FE60 /* UIImage+GIF.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+GIF.h"; path = "SDWebImage/UIImage+GIF.h"; sourceTree = ""; }; + 6708838356B19F3CE6CC1DB597AF05C0 /* ObjectMapper-watchOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "ObjectMapper-watchOS-dummy.m"; path = "../ObjectMapper-watchOS/ObjectMapper-watchOS-dummy.m"; sourceTree = ""; }; + 67340A7EFCE654D4C23EAF007F66C19E /* URLTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = URLTransform.swift; path = Sources/URLTransform.swift; sourceTree = ""; }; + 697F8F18238B03CD61C66E641D381323 /* AlamofireObjectMapper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AlamofireObjectMapper.swift; path = AlamofireObjectMapper/AlamofireObjectMapper.swift; sourceTree = ""; }; + 6B38173AAE3F4E4D4C374AA2AAF68276 /* DataTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DataTransform.swift; path = Sources/DataTransform.swift; sourceTree = ""; }; + 6B5EC70BFF0AB9EE7D13152B0E1ABE1C /* TransformType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TransformType.swift; path = Sources/TransformType.swift; sourceTree = ""; }; + 6C395ADF15FB8CC5203C1D322A051553 /* SDWebImageGIFCoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageGIFCoder.m; path = SDWebImage/SDWebImageGIFCoder.m; sourceTree = ""; }; + 6D31C620E17F575E6E2F90BC9D2A29AC /* FromJSON.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FromJSON.swift; path = Sources/FromJSON.swift; sourceTree = ""; }; + 6EB2DAEE85797D98DA0F7D5D10DEDFA6 /* Pods-BSRadioWaves.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-BSRadioWaves.modulemap"; sourceTree = ""; }; + 6EFA2D0F1DC58334781AF7D50B53FAC5 /* SDWebImageDownloader.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageDownloader.m; path = SDWebImage/SDWebImageDownloader.m; sourceTree = ""; }; + 6F1237FA10AC9A3ECB0203D8A4DF99A1 /* GCM.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = GCM.swift; path = Sources/CryptoSwift/BlockMode/GCM.swift; sourceTree = ""; }; + 6FE948AF72E43DA87B86E6EE34844AA7 /* EnumTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EnumTransform.swift; path = Sources/EnumTransform.swift; sourceTree = ""; }; + 703E96EE2BF1D60C4000FD01F5B67C89 /* CryptoSwift-iOS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "CryptoSwift-iOS-Info.plist"; sourceTree = ""; }; + 70B1C8CC6167248D84957B7ADA1E0244 /* CTR.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CTR.swift; path = Sources/CryptoSwift/BlockMode/CTR.swift; sourceTree = ""; }; + 72B47D8C7CEFFB9E6A3FB7ACC13BBB75 /* SDWebImage-iOS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SDWebImage-iOS-Info.plist"; sourceTree = ""; }; + 72E2B6C6AAA2FC3B536F80138DBFD0A1 /* ObjectMapper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ObjectMapper.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7488CC03C7AF2811382B42B0EF56FF40 /* SDWebImage-iOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SDWebImage-iOS-prefix.pch"; sourceTree = ""; }; + 757FF0BF3BF390A8D5EA34773154614D /* UIImageView+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImageView+WebCache.h"; path = "SDWebImage/UIImageView+WebCache.h"; sourceTree = ""; }; + 7648D746B888CAE88B320285E4D3476C /* AlamofireObjectMapper-watchOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "AlamofireObjectMapper-watchOS-umbrella.h"; path = "../AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-umbrella.h"; sourceTree = ""; }; + 773C7DCD3A6D2C43B7F7FEA7F3D4D25A /* StreamDecryptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StreamDecryptor.swift; path = Sources/CryptoSwift/StreamDecryptor.swift; sourceTree = ""; }; + 790FEA4A05DD92EE9916842AF2EDD8C3 /* CFB.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CFB.swift; path = Sources/CryptoSwift/BlockMode/CFB.swift; sourceTree = ""; }; + 799EBBE8EA9380002541B3BDC2509DFA /* Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Sources/CryptoSwift/Operators.swift; sourceTree = ""; }; + 7A0C50437972D72F88FBD1569D9F259D /* Array+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Array+Extension.swift"; path = "Sources/CryptoSwift/Array+Extension.swift"; sourceTree = ""; }; + 7A46A7D9CED5FA4156C5A1DE790FEC3C /* SDImageCacheConfig.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDImageCacheConfig.m; path = SDWebImage/SDImageCacheConfig.m; sourceTree = ""; }; + 7AE4A55F1AB2AFA507296B580FEC587C /* Response.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Response.swift; path = Source/Response.swift; sourceTree = ""; }; + 7AEDF7D8385F0270E5D3BC9E10F3B0E1 /* Bit.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Bit.swift; path = Sources/CryptoSwift/Bit.swift; sourceTree = ""; }; + 7C1ACDE5D1D241CCC9F542B8529DDCBC /* ObjectMapper-iOS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ObjectMapper-iOS-Info.plist"; sourceTree = ""; }; + 7C8BB3749670E28B26AE6AD0F877E3BA /* UInt64+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UInt64+Extension.swift"; path = "Sources/CryptoSwift/UInt64+Extension.swift"; sourceTree = ""; }; + 7CA2EE4ABF8769574D46F419F7513E7D /* HMAC.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HMAC.swift; path = Sources/CryptoSwift/HMAC.swift; sourceTree = ""; }; + 7CA95DDF2A57AADC3E6B6647C6A5F39F /* HexColorTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HexColorTransform.swift; path = Sources/HexColorTransform.swift; sourceTree = ""; }; + 7CC0AABB51E0E51C0E0A59F4615CC6D3 /* AlamofireObjectMapper-iOS.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "AlamofireObjectMapper-iOS.xcconfig"; sourceTree = ""; }; + 7DE20B76C04AA5CF2B9733747FA8611F /* NSButton+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSButton+WebCache.m"; path = "SDWebImage/NSButton+WebCache.m"; sourceTree = ""; }; + 7DF89231999CD17564BBD2E53963AE6E /* AFError.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AFError.swift; path = Source/AFError.swift; sourceTree = ""; }; + 81502D6196EAB1D8EDDF3FF070D40A05 /* UIImage+ForceDecode.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+ForceDecode.m"; path = "SDWebImage/UIImage+ForceDecode.m"; sourceTree = ""; }; + 81B658E690B21A3A9E181A0ABB6E5E70 /* UIView+WebCacheOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCacheOperation.h"; path = "SDWebImage/UIView+WebCacheOperation.h"; sourceTree = ""; }; + 820C57EB7696886472978F85CA00C503 /* Pods-Watch Extension-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-Watch Extension-umbrella.h"; sourceTree = ""; }; + 83403244CDF477D6E50171D9E3F24ABA /* AlamofireObjectMapper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AlamofireObjectMapper.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8411016B0FBF632DC10A7F987F66E1CB /* DigestType.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DigestType.swift; path = Sources/CryptoSwift/DigestType.swift; sourceTree = ""; }; + 843717451DD664682B1546AE807018DB /* SDWebImage-watchOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "SDWebImage-watchOS-dummy.m"; path = "../SDWebImage-watchOS/SDWebImage-watchOS-dummy.m"; sourceTree = ""; }; + 84F2BF12B2417E7E9CA801120E04FB7E /* DispatchQueue+Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "DispatchQueue+Alamofire.swift"; path = "Source/DispatchQueue+Alamofire.swift"; sourceTree = ""; }; + 84FE771131293A9CF3CC3B1F6B3BE5D5 /* Toast-Swift-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Toast-Swift-umbrella.h"; sourceTree = ""; }; + 8632EDFC946676A1D1A292794D61D782 /* Alamofire-watchOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "Alamofire-watchOS-umbrella.h"; path = "../Alamofire-watchOS/Alamofire-watchOS-umbrella.h"; sourceTree = ""; }; + 8633315FBBD3CD0F635B0D8D3F3AFD36 /* Alamofire-watchOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "Alamofire-watchOS-dummy.m"; path = "../Alamofire-watchOS/Alamofire-watchOS-dummy.m"; sourceTree = ""; }; + 87E6C9F2F10891B6C1D7116A2E3CD8B9 /* MapError.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MapError.swift; path = Sources/MapError.swift; sourceTree = ""; }; + 89F55E53A7E33823B2E6DD656AE2D71F /* SDWebImageFrame.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageFrame.h; path = SDWebImage/SDWebImageFrame.h; sourceTree = ""; }; + 89F8D45050B050498DEEB1FE8142B1ED /* NSData+ImageContentType.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSData+ImageContentType.h"; path = "SDWebImage/NSData+ImageContentType.h"; sourceTree = ""; }; + 8A0CC2ACCC6BB85FABA3E21D2428AEFA /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/ImageIO.framework; sourceTree = DEVELOPER_DIR; }; + 8A2B59600CBB0DAC804DC5AFACC939EF /* ObjectMapper-watchOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; name = "ObjectMapper-watchOS.modulemap"; path = "../ObjectMapper-watchOS/ObjectMapper-watchOS.modulemap"; sourceTree = ""; }; + 8AEC4674D34D88026D83CC62A515512B /* UIImage+MemoryCacheCost.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIImage+MemoryCacheCost.h"; path = "SDWebImage/UIImage+MemoryCacheCost.h"; sourceTree = ""; }; + 8B39E7D5BB0862C62CDC4FF1A2F399A1 /* CMAC.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CMAC.swift; path = Sources/CryptoSwift/CMAC.swift; sourceTree = ""; }; + 8C1A9A84A5151F6158459DBB5A1F72D5 /* NSImage+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSImage+WebCache.m"; path = "SDWebImage/NSImage+WebCache.m"; sourceTree = ""; }; + 8D15C250294C4B5E1EE5502CD51CD0B3 /* DateTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DateTransform.swift; path = Sources/DateTransform.swift; sourceTree = ""; }; + 8D60B50A48DA2FE4BEC4632019494C5B /* Collection+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Collection+Extension.swift"; path = "Sources/CryptoSwift/Collection+Extension.swift"; sourceTree = ""; }; + 8E380384FDB5D1D213E9381C8595090A /* ObjectMapper-iOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "ObjectMapper-iOS.modulemap"; sourceTree = ""; }; + 8EC1117E36EC72700C886B6C907A7408 /* SDWebImageManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageManager.m; path = SDWebImage/SDWebImageManager.m; sourceTree = ""; }; + 908B397C63C8C34F165CAD8E07B2B429 /* CipherModeWorker.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CipherModeWorker.swift; path = Sources/CryptoSwift/BlockMode/CipherModeWorker.swift; sourceTree = ""; }; + 914A98F250AD776F45A885D1B3D91DE0 /* SDWebImageTransition.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageTransition.h; path = SDWebImage/SDWebImageTransition.h; sourceTree = ""; }; + 91D130F38253D5A09A952C63F39991D6 /* Pods-Watch Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-Watch Extension.debug.xcconfig"; sourceTree = ""; }; + 926596AFB312264077D5F2C104BA5236 /* Pods-BSRadioWaves-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-BSRadioWaves-acknowledgements.markdown"; sourceTree = ""; }; + 926E31D5ADF72105FA3C33197139C3D2 /* UIButton+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIButton+WebCache.h"; path = "SDWebImage/UIButton+WebCache.h"; sourceTree = ""; }; + 943077C55D579E24267EC6C5B0454DFD /* SDImageCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDImageCache.m; path = SDWebImage/SDImageCache.m; sourceTree = ""; }; + 94B0295AEBC7F3211F22028415362C95 /* CCM.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CCM.swift; path = Sources/CryptoSwift/BlockMode/CCM.swift; sourceTree = ""; }; + 966AA42878212207687E9A2A4DBCD618 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9720BAAF7DC2D2F0AC082B1A100BC164 /* Updatable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Updatable.swift; path = Sources/CryptoSwift/Updatable.swift; sourceTree = ""; }; + 983B20F28DB35492E332811D7A13AC98 /* SDWebImage-watchOS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "SDWebImage-watchOS-Info.plist"; path = "../SDWebImage-watchOS/SDWebImage-watchOS-Info.plist"; sourceTree = ""; }; + 9C64A422373DB6A64CB548996A5CD141 /* CompactMap.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CompactMap.swift; path = Sources/CryptoSwift/CompactMap.swift; sourceTree = ""; }; + 9CCC8182E432EFE46A02256C7EB6D564 /* Checksum.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Checksum.swift; path = Sources/CryptoSwift/Checksum.swift; sourceTree = ""; }; + 9CF7B313C950060E72CDF22F0A0BB88F /* Alamofire-iOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Alamofire-iOS-prefix.pch"; sourceTree = ""; }; + 9D7D233D62F79E62FFA2EC91ACF06C04 /* SDWebImageCoderHelper.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageCoderHelper.m; path = SDWebImage/SDWebImageCoderHelper.m; sourceTree = ""; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9F59BDCA3709C6225FE577FBFA09A656 /* UIImage+MemoryCacheCost.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+MemoryCacheCost.m"; path = "SDWebImage/UIImage+MemoryCacheCost.m"; sourceTree = ""; }; + 9FB5CE6CC897D348D068D5DB80E1B6EC /* String+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "String+Extension.swift"; path = "Sources/CryptoSwift/String+Extension.swift"; sourceTree = ""; }; + A0A53F4EDA002C9FBBE33208D441E01F /* SDWebImageOperation.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageOperation.h; path = SDWebImage/SDWebImageOperation.h; sourceTree = ""; }; + A0AC9DD97964FA91D93CA6221978608D /* SDWebImage-iOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SDWebImage-iOS-dummy.m"; sourceTree = ""; }; + A379D3C523FB33338113A30BD5AE4148 /* ChaCha20.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChaCha20.swift; path = Sources/CryptoSwift/ChaCha20.swift; sourceTree = ""; }; + A3B80E4AF948917D76BC73171318A007 /* Rabbit.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Rabbit.swift; path = Sources/CryptoSwift/Rabbit.swift; sourceTree = ""; }; + A7F732E7DFBACF95DEF0785AB7461AED /* Pods-Watch Extension.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-Watch Extension.modulemap"; sourceTree = ""; }; + A8C5C58AD00C41F3B2BAE57C718CE33D /* SHA1.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SHA1.swift; path = Sources/CryptoSwift/SHA1.swift; sourceTree = ""; }; + AA230FA10E148D436F0096A332E674F2 /* UIImage+GIF.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImage+GIF.m"; path = "SDWebImage/UIImage+GIF.m"; sourceTree = ""; }; + AAEBB50390AA61AD781599F0627E4C4B /* Operators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Operators.swift; path = Sources/Operators.swift; sourceTree = ""; }; + AB0407015DEE2575F91C4C608D1B686D /* ZeroPadding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ZeroPadding.swift; path = Sources/CryptoSwift/ZeroPadding.swift; sourceTree = ""; }; + AB7A5ADD204B71124FE48C814E42B27F /* CustomDateFormatTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CustomDateFormatTransform.swift; path = Sources/CustomDateFormatTransform.swift; sourceTree = ""; }; + ABD1CE72B66B1C49F0FF065F377D5D1D /* CryptoSwift-iOS.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "CryptoSwift-iOS.xcconfig"; sourceTree = ""; }; + AC2A4E30DAEFFBE606F12B74951BDD8A /* Blowfish.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Blowfish.swift; path = Sources/CryptoSwift/Blowfish.swift; sourceTree = ""; }; + AD5FD21F2244C398C1CED5192CBEC6B4 /* CryptoSwift-iOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "CryptoSwift-iOS.modulemap"; sourceTree = ""; }; + ADD5E5583AA88157F0956EFFC762F822 /* Toast-Swift.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Toast-Swift.xcconfig"; sourceTree = ""; }; + B003740CA11B7CEBD2659F4A18CBDB00 /* AlamofireObjectMapper-watchOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "AlamofireObjectMapper-watchOS-prefix.pch"; path = "../AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-prefix.pch"; sourceTree = ""; }; + B1F7E0DFCE68F32BCE5F5B3FA45BE3F4 /* AlamofireObjectMapper-watchOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; name = "AlamofireObjectMapper-watchOS.modulemap"; path = "../AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.modulemap"; sourceTree = ""; }; + B488C5F5836A8E73CFC8CA67FDEF982D /* HKDF.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HKDF.swift; path = Sources/CryptoSwift/HKDF.swift; sourceTree = ""; }; + B6DDD81CB1DDDFBB355B0C40898AAD15 /* ObjectMapper-watchOS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "ObjectMapper-watchOS-Info.plist"; path = "../ObjectMapper-watchOS/ObjectMapper-watchOS-Info.plist"; sourceTree = ""; }; + B77F90AF101152500DC0C09450E3BE07 /* SecureBytes.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SecureBytes.swift; path = Sources/CryptoSwift/SecureBytes.swift; sourceTree = ""; }; + B78C1CBD3175E21DEA630033F390D15B /* NSButton+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSButton+WebCache.h"; path = "SDWebImage/NSButton+WebCache.h"; sourceTree = ""; }; + B95A06DCBDC16600A14C4677F1D0521E /* Toast-Swift.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Toast-Swift.modulemap"; sourceTree = ""; }; + BA052F80295C9ADE2DEBDCD35A7D8B8C /* Alamofire.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Alamofire.swift; path = Source/Alamofire.swift; sourceTree = ""; }; + BC5525591C4639FA428EAEB065CE90DD /* Pods-BSRadioWaves-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-BSRadioWaves-umbrella.h"; sourceTree = ""; }; + BCDF52BDB380C340B3D3DAE01DF1FD66 /* PKCS5.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PKCS5.swift; path = Sources/CryptoSwift/PKCS/PKCS5.swift; sourceTree = ""; }; + BCED4393BF6FB333978C434865EE9FBC /* SDAnimatedImageRep.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDAnimatedImageRep.m; path = SDWebImage/SDAnimatedImageRep.m; sourceTree = ""; }; + BDE035DE4FCEEEBC1953E0E37C0948E6 /* AlamofireObjectMapper-watchOS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "AlamofireObjectMapper-watchOS-Info.plist"; path = "../AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-Info.plist"; sourceTree = ""; }; + BE4572688292058D24E25808BFB7F214 /* OFB.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OFB.swift; path = Sources/CryptoSwift/BlockMode/OFB.swift; sourceTree = ""; }; + BE93082785221668B0DF44977020973C /* PCBC.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PCBC.swift; path = Sources/CryptoSwift/BlockMode/PCBC.swift; sourceTree = ""; }; + BFBE462ECF236FE4293B18544541364A /* SDWebImageCoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageCoder.m; path = SDWebImage/SDWebImageCoder.m; sourceTree = ""; }; + C0312205F7DFEECFAA5D36AA6DB32459 /* BatchedCollection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BatchedCollection.swift; path = Sources/CryptoSwift/BatchedCollection.swift; sourceTree = ""; }; + C15A47D715F6B15E5149A633B9C36EFE /* AES+Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "AES+Foundation.swift"; path = "Sources/CryptoSwift/Foundation/AES+Foundation.swift"; sourceTree = ""; }; + C1A3FAEEE74C5DD88B7F36BB5F750427 /* Pods_Watch_Extension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Watch_Extension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C6C3D9547308DB93D42D38DAC51DAF8A /* Alamofire-iOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Alamofire-iOS-dummy.m"; sourceTree = ""; }; + CA70E787EB2E6A5895307AAE2E288E68 /* ObjectMapper-iOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ObjectMapper-iOS-umbrella.h"; sourceTree = ""; }; + CBD91AC822910EC52639A4A2C7358026 /* SDWebImagePrefetcher.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImagePrefetcher.m; path = SDWebImage/SDWebImagePrefetcher.m; sourceTree = ""; }; + CC73C6B98C768EC395622233EB32D86F /* UIView+WebCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "UIView+WebCache.h"; path = "SDWebImage/UIView+WebCache.h"; sourceTree = ""; }; + CC8CAF1B4E8684CEC2A1DD43A2CD3B4F /* Poly1305.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Poly1305.swift; path = Sources/CryptoSwift/Poly1305.swift; sourceTree = ""; }; + CE2762DCE84D02C12B44357EF970B68C /* SDWebImageImageIOCoder.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageImageIOCoder.m; path = SDWebImage/SDWebImageImageIOCoder.m; sourceTree = ""; }; + CFDE164DAA6A067E81B4D6E89B59850E /* AES.Cryptors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AES.Cryptors.swift; path = Sources/CryptoSwift/AES.Cryptors.swift; sourceTree = ""; }; + CFF06E53BC38C0114EDAF51F6C433D9F /* SDWebImage.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImage.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D19F4243CB2ED9AEDBC8118906A92318 /* AlamofireObjectMapper-iOS-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "AlamofireObjectMapper-iOS-dummy.m"; sourceTree = ""; }; + D1A15C0955F3655BC85CE5A74E77F47A /* SDWebImageCodersManager.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageCodersManager.m; path = SDWebImage/SDWebImageCodersManager.m; sourceTree = ""; }; + D1C4D6B05FA28502B9D397B0CB89DE79 /* Pods-Watch Extension-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Watch Extension-frameworks.sh"; sourceTree = ""; }; + D1FA40437AAEE28861434F3586121072 /* Pods-Watch Extension-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Watch Extension-Info.plist"; sourceTree = ""; }; + D2B044125FB9727CC592AF1BFF2CC2F2 /* NoPadding.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = NoPadding.swift; path = Sources/CryptoSwift/NoPadding.swift; sourceTree = ""; }; + D2CDCE9F4E104ACC626EEEF1A601E4CD /* IntegerOperators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IntegerOperators.swift; path = Sources/IntegerOperators.swift; sourceTree = ""; }; + D2E7AF8AC40B27BA2991821B730888DC /* Alamofire-iOS.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Alamofire-iOS.modulemap"; sourceTree = ""; }; + D34F2E10923BD125CC6DAA118EAA5435 /* NSData+ImageContentType.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSData+ImageContentType.m"; path = "SDWebImage/NSData+ImageContentType.m"; sourceTree = ""; }; + D498EE4B8D4EAA6E7038D01E4D8EB88E /* SDWebImageManager.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageManager.h; path = SDWebImage/SDWebImageManager.h; sourceTree = ""; }; + D5B9891757DED528F5331BE36C99DB21 /* AlamofireObjectMapper-watchOS.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "AlamofireObjectMapper-watchOS.xcconfig"; path = "../AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.xcconfig"; sourceTree = ""; }; + D6043471C96F93DC41F7DD1E0D7D8B35 /* Toast_Swift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Toast_Swift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D6509D88F413480F9B11247D7A31549A /* SDWebImageDownloader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageDownloader.h; path = SDWebImage/SDWebImageDownloader.h; sourceTree = ""; }; + D81E5B8D26D74BF2801428771F138F4F /* SDWebImage-watchOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "SDWebImage-watchOS-prefix.pch"; path = "../SDWebImage-watchOS/SDWebImage-watchOS-prefix.pch"; sourceTree = ""; }; + D9013A862AF262415FEFEA092ABAB371 /* AlamofireObjectMapper-iOS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "AlamofireObjectMapper-iOS-Info.plist"; sourceTree = ""; }; + DBDBD728D03FE5744226369751BB8C8B /* CryptoSwift-watchOS-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "CryptoSwift-watchOS-Info.plist"; path = "../CryptoSwift-watchOS/CryptoSwift-watchOS-Info.plist"; sourceTree = ""; }; + DC267E6F43516A7C27F06B035D869846 /* CryptoSwift-watchOS.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "CryptoSwift-watchOS.xcconfig"; path = "../CryptoSwift-watchOS/CryptoSwift-watchOS.xcconfig"; sourceTree = ""; }; + DC509E11825E5D0085456E6886E813C1 /* Toast-Swift-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Toast-Swift-dummy.m"; sourceTree = ""; }; + E0C58AF4C5EF2B62E51F334483C0F585 /* Toast-Swift-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Toast-Swift-prefix.pch"; sourceTree = ""; }; + E163351D4E2C8D729AA52C9E28A394FE /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/WatchOS.platform/Developer/SDKs/WatchOS5.2.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + E2C55A5F184670CD2D61B8ACC7D22EA7 /* UIView+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIView+WebCache.m"; path = "SDWebImage/UIView+WebCache.m"; sourceTree = ""; }; + E2DE0DEA3DD6A454F97CBB492C8261F4 /* CryptoSwift-iOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "CryptoSwift-iOS-prefix.pch"; sourceTree = ""; }; + E3D5C30DCE7867365039FD693D17E6D1 /* SDWebImageImageIOCoder.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDWebImageImageIOCoder.h; path = SDWebImage/SDWebImageImageIOCoder.h; sourceTree = ""; }; + E4136293AF5C2A5645461EBE3091D1C6 /* MultipartFormData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MultipartFormData.swift; path = Source/MultipartFormData.swift; sourceTree = ""; }; + E55B679DF089154E9E3155339161B9C0 /* Alamofire-iOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Alamofire-iOS-umbrella.h"; sourceTree = ""; }; + E576DE9C1B8474304A4A7807AE657421 /* SDImageCache.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SDImageCache.h; path = SDWebImage/SDImageCache.h; sourceTree = ""; }; + E75DAC3FBE2F56D4034358964653F5BD /* CryptoSwift-watchOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "CryptoSwift-watchOS-prefix.pch"; path = "../CryptoSwift-watchOS/CryptoSwift-watchOS-prefix.pch"; sourceTree = ""; }; + E89C8A01AB215C4CC0EEE275E16AE147 /* Pods-Watch Extension-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-Watch Extension-acknowledgements.plist"; sourceTree = ""; }; + E8D2FFE8BB73DE0387C92C95013346E7 /* StreamEncryptor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = StreamEncryptor.swift; path = Sources/CryptoSwift/StreamEncryptor.swift; sourceTree = ""; }; + EE0DA179FAD7A331AED02CEE24C70925 /* Utils+Foundation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Utils+Foundation.swift"; path = "Sources/CryptoSwift/Foundation/Utils+Foundation.swift"; sourceTree = ""; }; + EEB78B7A16086FD0A25EACF4BD9D3BBA /* ObjectMapper-watchOS.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "ObjectMapper-watchOS.xcconfig"; path = "../ObjectMapper-watchOS/ObjectMapper-watchOS.xcconfig"; sourceTree = ""; }; + F02C9C48A7A2C8407E3F514BCFD9335D /* Int+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "Int+Extension.swift"; path = "Sources/CryptoSwift/Int+Extension.swift"; sourceTree = ""; }; + F094557EED3C2FD9C3C689756D00C385 /* AEADChaCha20Poly1305.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AEADChaCha20Poly1305.swift; path = Sources/CryptoSwift/AEAD/AEADChaCha20Poly1305.swift; sourceTree = ""; }; + F0CC03C39DD572AE7054563A188AF245 /* Timeline.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Timeline.swift; path = Source/Timeline.swift; sourceTree = ""; }; + F0F4A73853B69418C200A0180A7FC4DB /* ServerTrustPolicy.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ServerTrustPolicy.swift; path = Source/ServerTrustPolicy.swift; sourceTree = ""; }; + F1218EBF99FA63A965FB34486DB7C7F3 /* AlamofireObjectMapper-iOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "AlamofireObjectMapper-iOS-umbrella.h"; sourceTree = ""; }; + F135091FE0197253E94F3A7A342CDF58 /* DateFormatterTransform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DateFormatterTransform.swift; path = Sources/DateFormatterTransform.swift; sourceTree = ""; }; + F197377846D1C807408A25308E5E10AE /* SDWebImageTransition.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SDWebImageTransition.m; path = SDWebImage/SDWebImageTransition.m; sourceTree = ""; }; + F23837990984900FE72488992448FDAC /* UIImageView+WebCache.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "UIImageView+WebCache.m"; path = "SDWebImage/UIImageView+WebCache.m"; sourceTree = ""; }; + F2DE6CE475EA18FEECF0A57C67576A88 /* Mappable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Mappable.swift; path = Sources/Mappable.swift; sourceTree = ""; }; + F3127E182056505DD5B33AD124A8F6B1 /* Request.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Request.swift; path = Source/Request.swift; sourceTree = ""; }; + F4D5CF5092130A6E395AF669B51A2C1A /* CryptoSwift-watchOS-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "CryptoSwift-watchOS-umbrella.h"; path = "../CryptoSwift-watchOS/CryptoSwift-watchOS-umbrella.h"; sourceTree = ""; }; + F6016CF43C0B2D31043ADD65889FBB42 /* EnumOperators.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = EnumOperators.swift; path = Sources/EnumOperators.swift; sourceTree = ""; }; + F60A0F17365215CD2E821F7C5150FF7D /* Scrypt.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Scrypt.swift; path = Sources/CryptoSwift/Scrypt.swift; sourceTree = ""; }; + F67BA910C156D91489B8E49AC6550B7F /* Pods-BSRadioWaves-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-BSRadioWaves-dummy.m"; sourceTree = ""; }; + F77DAE94554B83C00E063A5804930878 /* Pods-Watch Extension-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-Watch Extension-dummy.m"; sourceTree = ""; }; + F8548C09A1A91E9A78E396912E7341AC /* Mapper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Mapper.swift; path = Sources/Mapper.swift; sourceTree = ""; }; + F8BB518F28ADFEE77882182599D83183 /* ObjectMapper-iOS-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "ObjectMapper-iOS-prefix.pch"; sourceTree = ""; }; + FA160AA3138E9D4CCFBF58278868FD65 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; + FA3483723D40955DEACECCC483FB9AC7 /* ECB.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ECB.swift; path = Sources/CryptoSwift/BlockMode/ECB.swift; sourceTree = ""; }; + FB7EAA2156AED0A96332A66A1C079425 /* Pods-BSRadioWaves.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-BSRadioWaves.release.xcconfig"; sourceTree = ""; }; + FBA93C0676F4CFA61B1FC6FD7912934C /* UInt32+Extension.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UInt32+Extension.swift"; path = "Sources/CryptoSwift/UInt32+Extension.swift"; sourceTree = ""; }; + FCF8325A35C0DCE5CBE4E54CB9076259 /* Generics.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Generics.swift; path = Sources/CryptoSwift/Generics.swift; sourceTree = ""; }; + FD5775FAC65F3B1EDD0EDA8737972FB2 /* AES.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AES.swift; path = Sources/CryptoSwift/AES.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 04B4849F1FFDB6B2A1089C928FB7BC0C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 11FDC1963D6CDC1B520B4AA792132DEB /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 152219B0468DDEDC15A7E8759DF2FB2F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + FC6BB17D15EC8A4D2134D858B3A7F415 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 167A0432F4E911437466D3A9AD3EEBD5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ABB633F1FA37ADCBFC48F2399B84EF60 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1D05D89C7E09239776CE173343A5EEDD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0B86CB58612CC8E19C34E34C7C9A5655 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 366BAEF20D927232D8C36EB300DE337D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 66600C86BB2CF249F5C34343311573C0 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3D4F61692D905FF0934E576DDF5C775E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6051FE9A068EC8298411D6007BB357A7 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 51C49E6511B1FE5314E69AD783B2DF18 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 6820FC9C4AEE3F77DD0E587E4600A9E9 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6102CF7EA55F5A7D669F88BF0D1A701F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 95ACABC71585D657249CC92BA7731A8F /* Foundation.framework in Frameworks */, + C06D290B9216533843023A0BF93F5927 /* QuartzCore.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 80CC111D5A09EBD3E97F6D9B4F66B40C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BAEE814157F78C267981190CCCAE0AFE /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + AF03E7B12542EB9BB4E6BE5E2056ABC0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B3D2380657D0565B887DBED07ABBE022 /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + DAFDF3E5D36B5892FDFE65BB75AF9ABB /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 27CC4E8B16E46E400437A10F13994AC5 /* Foundation.framework in Frameworks */, + 368229A1AF8392BFEF77534F67B242F5 /* ImageIO.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E602E9FC4404EA63875018424E0FBD68 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DA0C259DA7E7D1791A93FA61BD6EB1EB /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F207463F944742D651704A02BA815208 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DF47FAC7F3F8A969D9F9EE47410E1B93 /* Foundation.framework in Frameworks */, + 06E003B32DF139847C7FF7B143AA5211 /* ImageIO.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0837CA9030AB11CFCE9EE76659490723 /* Support Files */ = { + isa = PBXGroup; + children = ( + B95A06DCBDC16600A14C4677F1D0521E /* Toast-Swift.modulemap */, + ADD5E5583AA88157F0956EFFC762F822 /* Toast-Swift.xcconfig */, + DC509E11825E5D0085456E6886E813C1 /* Toast-Swift-dummy.m */, + 23C0C5B89A668B8EB9F7A5DDF4DF9C5B /* Toast-Swift-Info.plist */, + E0C58AF4C5EF2B62E51F334483C0F585 /* Toast-Swift-prefix.pch */, + 84FE771131293A9CF3CC3B1F6B3BE5D5 /* Toast-Swift-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/Toast-Swift"; + sourceTree = ""; + }; + 08CFDB531777735D44D271336170E70A /* SDWebImage */ = { + isa = PBXGroup; + children = ( + 8ADD1DDF78315287837B21A0D6BACDD8 /* Core */, + 44DE140711B5FDDDA0E7FDB5461CC4E2 /* Support Files */, + ); + path = SDWebImage; + sourceTree = ""; + }; + 090D0B8E693B459D6E7800142E520406 /* Pods */ = { + isa = PBXGroup; + children = ( + 6625F25572AE20D5A250AEB48EC4D526 /* Alamofire */, + 14796175713CBA86625D06527A5DFF12 /* AlamofireObjectMapper */, + BB9FAAACF547372FDDD5A8432006FC47 /* CryptoSwift */, + D9B9632714C8B145014AAA3C9269D76A /* ObjectMapper */, + 08CFDB531777735D44D271336170E70A /* SDWebImage */, + C07A244517F46DFB513C076259E8D41B /* Toast-Swift */, + ); + name = Pods; + sourceTree = ""; + }; + 14796175713CBA86625D06527A5DFF12 /* AlamofireObjectMapper */ = { + isa = PBXGroup; + children = ( + 697F8F18238B03CD61C66E641D381323 /* AlamofireObjectMapper.swift */, + 861A58112A2B756A91A11E1677199B3C /* Support Files */, + ); + path = AlamofireObjectMapper; + sourceTree = ""; + }; + 1F807054EC60536FFF737C4053489198 /* Pods-Watch Extension */ = { + isa = PBXGroup; + children = ( + A7F732E7DFBACF95DEF0785AB7461AED /* Pods-Watch Extension.modulemap */, + 2B55C727541578F1150E77E912FFEDE6 /* Pods-Watch Extension-acknowledgements.markdown */, + E89C8A01AB215C4CC0EEE275E16AE147 /* Pods-Watch Extension-acknowledgements.plist */, + F77DAE94554B83C00E063A5804930878 /* Pods-Watch Extension-dummy.m */, + D1C4D6B05FA28502B9D397B0CB89DE79 /* Pods-Watch Extension-frameworks.sh */, + D1FA40437AAEE28861434F3586121072 /* Pods-Watch Extension-Info.plist */, + 820C57EB7696886472978F85CA00C503 /* Pods-Watch Extension-umbrella.h */, + 91D130F38253D5A09A952C63F39991D6 /* Pods-Watch Extension.debug.xcconfig */, + 1F4753D1AB10D773CEF9839DE1B95FF4 /* Pods-Watch Extension.release.xcconfig */, + ); + name = "Pods-Watch Extension"; + path = "Target Support Files/Pods-Watch Extension"; + sourceTree = ""; + }; + 332447E364AF2138C3526C7D0B80E444 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 35A78511A408B14E32794F406A80BAF1 /* iOS */, + B334D4D95F10F3D3D5F793A631DB55D2 /* watchOS */, + ); + name = Frameworks; + sourceTree = ""; + }; + 35A78511A408B14E32794F406A80BAF1 /* iOS */ = { + isa = PBXGroup; + children = ( + FA160AA3138E9D4CCFBF58278868FD65 /* Foundation.framework */, + 8A0CC2ACCC6BB85FABA3E21D2428AEFA /* ImageIO.framework */, + 4E2D3E13915B9672343ACB9DE3D89DEC /* QuartzCore.framework */, + ); + name = iOS; + sourceTree = ""; + }; + 44DE140711B5FDDDA0E7FDB5461CC4E2 /* Support Files */ = { + isa = PBXGroup; + children = ( + 12181444875E1B28643E159F03510953 /* SDWebImage-iOS.modulemap */, + 17CAAB77FCDE6347454F7A923FD58ACE /* SDWebImage-iOS.xcconfig */, + A0AC9DD97964FA91D93CA6221978608D /* SDWebImage-iOS-dummy.m */, + 72B47D8C7CEFFB9E6A3FB7ACC13BBB75 /* SDWebImage-iOS-Info.plist */, + 7488CC03C7AF2811382B42B0EF56FF40 /* SDWebImage-iOS-prefix.pch */, + 40F50335C7F937505F15341FD4ADA2B5 /* SDWebImage-iOS-umbrella.h */, + 2F70ADFE3EBB5F53FFB56FC28B5EE670 /* SDWebImage-watchOS.modulemap */, + 2B3248A4BA39C7307B86266A2A7881B5 /* SDWebImage-watchOS.xcconfig */, + 843717451DD664682B1546AE807018DB /* SDWebImage-watchOS-dummy.m */, + 983B20F28DB35492E332811D7A13AC98 /* SDWebImage-watchOS-Info.plist */, + D81E5B8D26D74BF2801428771F138F4F /* SDWebImage-watchOS-prefix.pch */, + 43FB744D3A7CA2381CF940DFC5A5FD7F /* SDWebImage-watchOS-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/SDWebImage-iOS"; + sourceTree = ""; + }; + 54228CB59C6D2100842B406808DCD6E2 /* Support Files */ = { + isa = PBXGroup; + children = ( + D2E7AF8AC40B27BA2991821B730888DC /* Alamofire-iOS.modulemap */, + 3CA27772B0C1545A46B4A7DD89A4C8C8 /* Alamofire-iOS.xcconfig */, + C6C3D9547308DB93D42D38DAC51DAF8A /* Alamofire-iOS-dummy.m */, + 381AD64BFD13490931D50993631E4947 /* Alamofire-iOS-Info.plist */, + 9CF7B313C950060E72CDF22F0A0BB88F /* Alamofire-iOS-prefix.pch */, + E55B679DF089154E9E3155339161B9C0 /* Alamofire-iOS-umbrella.h */, + 42F09DC6B1358D384F6F21CCC835E790 /* Alamofire-watchOS.modulemap */, + 4BB746D5F5ED9B9B024F39461D914A43 /* Alamofire-watchOS.xcconfig */, + 8633315FBBD3CD0F635B0D8D3F3AFD36 /* Alamofire-watchOS-dummy.m */, + 3DC963D960B085F1307DF22177EBE772 /* Alamofire-watchOS-Info.plist */, + 347776958F66D7BED07270422D442946 /* Alamofire-watchOS-prefix.pch */, + 8632EDFC946676A1D1A292794D61D782 /* Alamofire-watchOS-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/Alamofire-iOS"; + sourceTree = ""; + }; + 60F2D91A9E66395C2807A1F42781A537 /* Pods-BSRadioWaves */ = { + isa = PBXGroup; + children = ( + 6EB2DAEE85797D98DA0F7D5D10DEDFA6 /* Pods-BSRadioWaves.modulemap */, + 926596AFB312264077D5F2C104BA5236 /* Pods-BSRadioWaves-acknowledgements.markdown */, + 54A29DBE2CDA7892674DD31F6E993B72 /* Pods-BSRadioWaves-acknowledgements.plist */, + F67BA910C156D91489B8E49AC6550B7F /* Pods-BSRadioWaves-dummy.m */, + 2D558011831313537E5FB9AAE0D11C1C /* Pods-BSRadioWaves-frameworks.sh */, + 2491F1715A5D6D43C0B16A1F5DAEB741 /* Pods-BSRadioWaves-Info.plist */, + BC5525591C4639FA428EAEB065CE90DD /* Pods-BSRadioWaves-umbrella.h */, + 30CAAA388CF42B22A57E09222AB587F3 /* Pods-BSRadioWaves.debug.xcconfig */, + FB7EAA2156AED0A96332A66A1C079425 /* Pods-BSRadioWaves.release.xcconfig */, + ); + name = "Pods-BSRadioWaves"; + path = "Target Support Files/Pods-BSRadioWaves"; + sourceTree = ""; + }; + 6625F25572AE20D5A250AEB48EC4D526 /* Alamofire */ = { + isa = PBXGroup; + children = ( + 7DF89231999CD17564BBD2E53963AE6E /* AFError.swift */, + BA052F80295C9ADE2DEBDCD35A7D8B8C /* Alamofire.swift */, + 84F2BF12B2417E7E9CA801120E04FB7E /* DispatchQueue+Alamofire.swift */, + E4136293AF5C2A5645461EBE3091D1C6 /* MultipartFormData.swift */, + 154B32DDA57B67BB85BE4EDC9F94D237 /* NetworkReachabilityManager.swift */, + 4BE51F59AA1FB91C91AF5CCB03EF5BBB /* Notifications.swift */, + 245CFE0D7E98B32922BCC4E1D7A71809 /* ParameterEncoding.swift */, + F3127E182056505DD5B33AD124A8F6B1 /* Request.swift */, + 7AE4A55F1AB2AFA507296B580FEC587C /* Response.swift */, + 33941F96D2513278A5F2225BC00F4B18 /* ResponseSerialization.swift */, + 472B024F353D47204165DCAEAF286DCF /* Result.swift */, + F0F4A73853B69418C200A0180A7FC4DB /* ServerTrustPolicy.swift */, + 18FB7555B50165984CBBB4A22E2E1425 /* SessionDelegate.swift */, + 1C0E1D8BB5A80DEE7944B70EBD304267 /* SessionManager.swift */, + 5058D4CAD4BA5182249468FCE66189B8 /* TaskDelegate.swift */, + F0CC03C39DD572AE7054563A188AF245 /* Timeline.swift */, + 42505EEE9F52E1B31ED6A637B15D7383 /* Validation.swift */, + 54228CB59C6D2100842B406808DCD6E2 /* Support Files */, + ); + path = Alamofire; + sourceTree = ""; + }; + 861A58112A2B756A91A11E1677199B3C /* Support Files */ = { + isa = PBXGroup; + children = ( + 06D8CFEF1266346B6B82C5B7AAF6FD89 /* AlamofireObjectMapper-iOS.modulemap */, + 7CC0AABB51E0E51C0E0A59F4615CC6D3 /* AlamofireObjectMapper-iOS.xcconfig */, + D19F4243CB2ED9AEDBC8118906A92318 /* AlamofireObjectMapper-iOS-dummy.m */, + D9013A862AF262415FEFEA092ABAB371 /* AlamofireObjectMapper-iOS-Info.plist */, + 3126072088DB1957115ADAAEB4BEA52D /* AlamofireObjectMapper-iOS-prefix.pch */, + F1218EBF99FA63A965FB34486DB7C7F3 /* AlamofireObjectMapper-iOS-umbrella.h */, + B1F7E0DFCE68F32BCE5F5B3FA45BE3F4 /* AlamofireObjectMapper-watchOS.modulemap */, + D5B9891757DED528F5331BE36C99DB21 /* AlamofireObjectMapper-watchOS.xcconfig */, + 223513C72298BB481E8F1B33DC47C0F0 /* AlamofireObjectMapper-watchOS-dummy.m */, + BDE035DE4FCEEEBC1953E0E37C0948E6 /* AlamofireObjectMapper-watchOS-Info.plist */, + B003740CA11B7CEBD2659F4A18CBDB00 /* AlamofireObjectMapper-watchOS-prefix.pch */, + 7648D746B888CAE88B320285E4D3476C /* AlamofireObjectMapper-watchOS-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/AlamofireObjectMapper-iOS"; + sourceTree = ""; + }; + 8A66F46EDBAC17B079E406AE67924FC5 /* Support Files */ = { + isa = PBXGroup; + children = ( + 8E380384FDB5D1D213E9381C8595090A /* ObjectMapper-iOS.modulemap */, + 56E95B11A8DE03F6CA005AD960DC0E2B /* ObjectMapper-iOS.xcconfig */, + 145A91E809AD1CE2702E3F4069A17127 /* ObjectMapper-iOS-dummy.m */, + 7C1ACDE5D1D241CCC9F542B8529DDCBC /* ObjectMapper-iOS-Info.plist */, + F8BB518F28ADFEE77882182599D83183 /* ObjectMapper-iOS-prefix.pch */, + CA70E787EB2E6A5895307AAE2E288E68 /* ObjectMapper-iOS-umbrella.h */, + 8A2B59600CBB0DAC804DC5AFACC939EF /* ObjectMapper-watchOS.modulemap */, + EEB78B7A16086FD0A25EACF4BD9D3BBA /* ObjectMapper-watchOS.xcconfig */, + 6708838356B19F3CE6CC1DB597AF05C0 /* ObjectMapper-watchOS-dummy.m */, + B6DDD81CB1DDDFBB355B0C40898AAD15 /* ObjectMapper-watchOS-Info.plist */, + 400AB493334D2934D760FC53237DF7C6 /* ObjectMapper-watchOS-prefix.pch */, + 1428B300F5C24951DC479A75C343EA14 /* ObjectMapper-watchOS-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/ObjectMapper-iOS"; + sourceTree = ""; + }; + 8ADD1DDF78315287837B21A0D6BACDD8 /* Core */ = { + isa = PBXGroup; + children = ( + B78C1CBD3175E21DEA630033F390D15B /* NSButton+WebCache.h */, + 7DE20B76C04AA5CF2B9733747FA8611F /* NSButton+WebCache.m */, + 89F8D45050B050498DEEB1FE8142B1ED /* NSData+ImageContentType.h */, + D34F2E10923BD125CC6DAA118EAA5435 /* NSData+ImageContentType.m */, + 078B8292D545DFE2C5CD938BCB812BF2 /* NSImage+WebCache.h */, + 8C1A9A84A5151F6158459DBB5A1F72D5 /* NSImage+WebCache.m */, + 389F6AE412BA3442C610F7AE0823BE3D /* SDAnimatedImageRep.h */, + BCED4393BF6FB333978C434865EE9FBC /* SDAnimatedImageRep.m */, + E576DE9C1B8474304A4A7807AE657421 /* SDImageCache.h */, + 943077C55D579E24267EC6C5B0454DFD /* SDImageCache.m */, + 61CB331B8CD0303E2231784911D66A13 /* SDImageCacheConfig.h */, + 7A46A7D9CED5FA4156C5A1DE790FEC3C /* SDImageCacheConfig.m */, + 3D502B6FDF14EB7F9077C2048BB9117F /* SDWebImageCoder.h */, + BFBE462ECF236FE4293B18544541364A /* SDWebImageCoder.m */, + 378FDDCE9E13EB010D91074AB4C18BF5 /* SDWebImageCoderHelper.h */, + 9D7D233D62F79E62FFA2EC91ACF06C04 /* SDWebImageCoderHelper.m */, + 6551AC70A6402369433BA24C84E9A435 /* SDWebImageCodersManager.h */, + D1A15C0955F3655BC85CE5A74E77F47A /* SDWebImageCodersManager.m */, + 6609A66E0D47DCD51DB0589EA61119C3 /* SDWebImageCompat.h */, + 5DB9CD2F0897EAF9893BF859B2D73C22 /* SDWebImageCompat.m */, + D6509D88F413480F9B11247D7A31549A /* SDWebImageDownloader.h */, + 6EFA2D0F1DC58334781AF7D50B53FAC5 /* SDWebImageDownloader.m */, + 53C394B42B7968A28414E19226D7BFB1 /* SDWebImageDownloaderOperation.h */, + 53CD26E0EC964DBCE766401B9E13A32F /* SDWebImageDownloaderOperation.m */, + 89F55E53A7E33823B2E6DD656AE2D71F /* SDWebImageFrame.h */, + 0F4663658088190E2706E86A72103A64 /* SDWebImageFrame.m */, + 0B5A801FD7920FCF7B684C7A4BFAF63A /* SDWebImageGIFCoder.h */, + 6C395ADF15FB8CC5203C1D322A051553 /* SDWebImageGIFCoder.m */, + E3D5C30DCE7867365039FD693D17E6D1 /* SDWebImageImageIOCoder.h */, + CE2762DCE84D02C12B44357EF970B68C /* SDWebImageImageIOCoder.m */, + D498EE4B8D4EAA6E7038D01E4D8EB88E /* SDWebImageManager.h */, + 8EC1117E36EC72700C886B6C907A7408 /* SDWebImageManager.m */, + A0A53F4EDA002C9FBBE33208D441E01F /* SDWebImageOperation.h */, + 4C36A385EA45E5291F09DB4C8396BC6F /* SDWebImagePrefetcher.h */, + CBD91AC822910EC52639A4A2C7358026 /* SDWebImagePrefetcher.m */, + 914A98F250AD776F45A885D1B3D91DE0 /* SDWebImageTransition.h */, + F197377846D1C807408A25308E5E10AE /* SDWebImageTransition.m */, + 926E31D5ADF72105FA3C33197139C3D2 /* UIButton+WebCache.h */, + 0CF19C129E29A610DB4B377B99E06B9C /* UIButton+WebCache.m */, + 1664B5B9254FBFC12EFAD7F013FE6970 /* UIImage+ForceDecode.h */, + 81502D6196EAB1D8EDDF3FF070D40A05 /* UIImage+ForceDecode.m */, + 66E5B19A3447183BDDEBB8C3D231FE60 /* UIImage+GIF.h */, + AA230FA10E148D436F0096A332E674F2 /* UIImage+GIF.m */, + 8AEC4674D34D88026D83CC62A515512B /* UIImage+MemoryCacheCost.h */, + 9F59BDCA3709C6225FE577FBFA09A656 /* UIImage+MemoryCacheCost.m */, + 4D817A21EC4523EBBBD1C2D8E17CED11 /* UIImage+MultiFormat.h */, + 492E42E49BAE2DDE8F7F547356939396 /* UIImage+MultiFormat.m */, + 00BE49C726548FF41D71F0AD2F2624B6 /* UIImageView+HighlightedWebCache.h */, + 20645947CE2E4DF76C0C21F0A4CC470B /* UIImageView+HighlightedWebCache.m */, + 757FF0BF3BF390A8D5EA34773154614D /* UIImageView+WebCache.h */, + F23837990984900FE72488992448FDAC /* UIImageView+WebCache.m */, + CC73C6B98C768EC395622233EB32D86F /* UIView+WebCache.h */, + E2C55A5F184670CD2D61B8ACC7D22EA7 /* UIView+WebCache.m */, + 81B658E690B21A3A9E181A0ABB6E5E70 /* UIView+WebCacheOperation.h */, + 35D46D44A4A590E3E369C91F5AD26C87 /* UIView+WebCacheOperation.m */, + ); + name = Core; + sourceTree = ""; + }; + 91C608E69B882981EFEC4E7DE95FCA82 /* Support Files */ = { + isa = PBXGroup; + children = ( + AD5FD21F2244C398C1CED5192CBEC6B4 /* CryptoSwift-iOS.modulemap */, + ABD1CE72B66B1C49F0FF065F377D5D1D /* CryptoSwift-iOS.xcconfig */, + 21FBF47F8C9900718A5776DB63DBF696 /* CryptoSwift-iOS-dummy.m */, + 703E96EE2BF1D60C4000FD01F5B67C89 /* CryptoSwift-iOS-Info.plist */, + E2DE0DEA3DD6A454F97CBB492C8261F4 /* CryptoSwift-iOS-prefix.pch */, + 46B8798D6E0EBDDD8226815DB42D53CA /* CryptoSwift-iOS-umbrella.h */, + 46381330451AB4591A668E6370CE74AB /* CryptoSwift-watchOS.modulemap */, + DC267E6F43516A7C27F06B035D869846 /* CryptoSwift-watchOS.xcconfig */, + 14F4FD10BB7A334B3B52ED6E3664ECC3 /* CryptoSwift-watchOS-dummy.m */, + DBDBD728D03FE5744226369751BB8C8B /* CryptoSwift-watchOS-Info.plist */, + E75DAC3FBE2F56D4034358964653F5BD /* CryptoSwift-watchOS-prefix.pch */, + F4D5CF5092130A6E395AF669B51A2C1A /* CryptoSwift-watchOS-umbrella.h */, + ); + name = "Support Files"; + path = "../Target Support Files/CryptoSwift-iOS"; + sourceTree = ""; + }; + B334D4D95F10F3D3D5F793A631DB55D2 /* watchOS */ = { + isa = PBXGroup; + children = ( + E163351D4E2C8D729AA52C9E28A394FE /* Foundation.framework */, + 4EA2B9E7598C53E3DB0F929D091814F0 /* ImageIO.framework */, + ); + name = watchOS; + sourceTree = ""; + }; + B854A1ACF1702E5C5FE7B970F8AF7449 /* Targets Support Files */ = { + isa = PBXGroup; + children = ( + 60F2D91A9E66395C2807A1F42781A537 /* Pods-BSRadioWaves */, + 1F807054EC60536FFF737C4053489198 /* Pods-Watch Extension */, + ); + name = "Targets Support Files"; + sourceTree = ""; + }; + BB9FAAACF547372FDDD5A8432006FC47 /* CryptoSwift */ = { + isa = PBXGroup; + children = ( + 31A0C06C72AC2BB4DA4355BAA129F8BF /* AEAD.swift */, + F094557EED3C2FD9C3C689756D00C385 /* AEADChaCha20Poly1305.swift */, + FD5775FAC65F3B1EDD0EDA8737972FB2 /* AES.swift */, + C15A47D715F6B15E5149A633B9C36EFE /* AES+Foundation.swift */, + CFDE164DAA6A067E81B4D6E89B59850E /* AES.Cryptors.swift */, + 7A0C50437972D72F88FBD1569D9F259D /* Array+Extension.swift */, + 3C66354493DBECB5149CAB1B8BAE892E /* Array+Foundation.swift */, + 24E3924369A79764E740EEAC21ACEA21 /* Authenticator.swift */, + C0312205F7DFEECFAA5D36AA6DB32459 /* BatchedCollection.swift */, + 7AEDF7D8385F0270E5D3BC9E10F3B0E1 /* Bit.swift */, + 64D0E31F7478A5D3CC1E0F67F71531EE /* BlockCipher.swift */, + 4887F39F9288BCE0542FEDF35B09ACB3 /* BlockDecryptor.swift */, + 3F662A585BB28AE3557F5C0968A8144A /* BlockEncryptor.swift */, + 4486FDC523F6036877D028ACC7575A91 /* BlockMode.swift */, + 2C26871F2127DFE55454DFB49C28A3FF /* BlockModeOptions.swift */, + AC2A4E30DAEFFBE606F12B74951BDD8A /* Blowfish.swift */, + 28C3BC66B278570FFDEE73352885A4CC /* Blowfish+Foundation.swift */, + 08F45D8ABEEC2A98771C4E897DAFC6A4 /* CBC.swift */, + 1B6F47AD390E6C7ABB618D40AFCECBE0 /* CBCMAC.swift */, + 94B0295AEBC7F3211F22028415362C95 /* CCM.swift */, + 790FEA4A05DD92EE9916842AF2EDD8C3 /* CFB.swift */, + A379D3C523FB33338113A30BD5AE4148 /* ChaCha20.swift */, + 23A0A9E23FB389361D3EFFD37AD3B744 /* ChaCha20+Foundation.swift */, + 9CCC8182E432EFE46A02256C7EB6D564 /* Checksum.swift */, + 397A89A1E00B8670B3F71320935E1342 /* Cipher.swift */, + 908B397C63C8C34F165CAD8E07B2B429 /* CipherModeWorker.swift */, + 8B39E7D5BB0862C62CDC4FF1A2F399A1 /* CMAC.swift */, + 8D60B50A48DA2FE4BEC4632019494C5B /* Collection+Extension.swift */, + 9C64A422373DB6A64CB548996A5CD141 /* CompactMap.swift */, + 24C0980CBE1EFBEF2247F08C12724914 /* Cryptor.swift */, + 4E05B6BBEC2DFE3C8152FA0893EF346B /* Cryptors.swift */, + 70B1C8CC6167248D84957B7ADA1E0244 /* CTR.swift */, + 1999E800D436061AA2CD5555C6A4698D /* Data+Extension.swift */, + 1E7F57F121D9B91B455E018464D636FE /* Digest.swift */, + 8411016B0FBF632DC10A7F987F66E1CB /* DigestType.swift */, + FA3483723D40955DEACECCC483FB9AC7 /* ECB.swift */, + 6F1237FA10AC9A3ECB0203D8A4DF99A1 /* GCM.swift */, + FCF8325A35C0DCE5CBE4E54CB9076259 /* Generics.swift */, + B488C5F5836A8E73CFC8CA67FDEF982D /* HKDF.swift */, + 7CA2EE4ABF8769574D46F419F7513E7D /* HMAC.swift */, + 47841E0B2A196904B1250178233B0C29 /* HMAC+Foundation.swift */, + F02C9C48A7A2C8407E3F514BCFD9335D /* Int+Extension.swift */, + 09C1556FAF37B97DFB2249475C26CAB5 /* MD5.swift */, + D2B044125FB9727CC592AF1BFF2CC2F2 /* NoPadding.swift */, + BE4572688292058D24E25808BFB7F214 /* OFB.swift */, + 799EBBE8EA9380002541B3BDC2509DFA /* Operators.swift */, + 47A280350348F5AB482446E0A01DE31E /* Padding.swift */, + 422CC1C0934FE7FC948E3569428B35ED /* PBKDF1.swift */, + 425747501EF0C921813B08642430C109 /* PBKDF2.swift */, + BE93082785221668B0DF44977020973C /* PCBC.swift */, + BCDF52BDB380C340B3D3DAE01DF1FD66 /* PKCS5.swift */, + 446A03A259525DA90A1935D4F9C81A9C /* PKCS7.swift */, + 205B852C5AEA3938C4D0682669465ABC /* PKCS7Padding.swift */, + CC8CAF1B4E8684CEC2A1DD43A2CD3B4F /* Poly1305.swift */, + A3B80E4AF948917D76BC73171318A007 /* Rabbit.swift */, + 12C26BA20945990CC20CCBCC08FC64E1 /* Rabbit+Foundation.swift */, + F60A0F17365215CD2E821F7C5150FF7D /* Scrypt.swift */, + B77F90AF101152500DC0C09450E3BE07 /* SecureBytes.swift */, + A8C5C58AD00C41F3B2BAE57C718CE33D /* SHA1.swift */, + 34BCBF8BD04E98F16D5391D774A4D5C1 /* SHA2.swift */, + 533C2539ADA8F13BB1BD294312BBB4AC /* SHA3.swift */, + 773C7DCD3A6D2C43B7F7FEA7F3D4D25A /* StreamDecryptor.swift */, + E8D2FFE8BB73DE0387C92C95013346E7 /* StreamEncryptor.swift */, + 9FB5CE6CC897D348D068D5DB80E1B6EC /* String+Extension.swift */, + 58706E4731DB31F7E51958134686A6EF /* String+FoundationExtension.swift */, + 53094347E1ABA3120D3AD1AA9180D872 /* UInt128.swift */, + 23CB7AD01B3AEF46B5390A8C2168CF21 /* UInt16+Extension.swift */, + FBA93C0676F4CFA61B1FC6FD7912934C /* UInt32+Extension.swift */, + 7C8BB3749670E28B26AE6AD0F877E3BA /* UInt64+Extension.swift */, + 3D25864C51D6CCE0C9E1EF1442594EEA /* UInt8+Extension.swift */, + 9720BAAF7DC2D2F0AC082B1A100BC164 /* Updatable.swift */, + 38D2955A508F53B2621EC6165CA16ACC /* Utils.swift */, + EE0DA179FAD7A331AED02CEE24C70925 /* Utils+Foundation.swift */, + AB0407015DEE2575F91C4C608D1B686D /* ZeroPadding.swift */, + 91C608E69B882981EFEC4E7DE95FCA82 /* Support Files */, + ); + path = CryptoSwift; + sourceTree = ""; + }; + C07A244517F46DFB513C076259E8D41B /* Toast-Swift */ = { + isa = PBXGroup; + children = ( + 028CE532624E25B101754545D1387E07 /* Toast.swift */, + 0837CA9030AB11CFCE9EE76659490723 /* Support Files */, + ); + path = "Toast-Swift"; + sourceTree = ""; + }; + CF1408CF629C7361332E53B88F7BD30C = { + isa = PBXGroup; + children = ( + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */, + 332447E364AF2138C3526C7D0B80E444 /* Frameworks */, + 090D0B8E693B459D6E7800142E520406 /* Pods */, + FD2E5414938C5E6992A842FFCCF24745 /* Products */, + B854A1ACF1702E5C5FE7B970F8AF7449 /* Targets Support Files */, + ); + sourceTree = ""; + }; + D9B9632714C8B145014AAA3C9269D76A /* ObjectMapper */ = { + isa = PBXGroup; + children = ( + 4D92F091DEF5B0921082C97AF24966C0 /* CodableTransform.swift */, + AB7A5ADD204B71124FE48C814E42B27F /* CustomDateFormatTransform.swift */, + 6B38173AAE3F4E4D4C374AA2AAF68276 /* DataTransform.swift */, + F135091FE0197253E94F3A7A342CDF58 /* DateFormatterTransform.swift */, + 8D15C250294C4B5E1EE5502CD51CD0B3 /* DateTransform.swift */, + 525C256AAFECE92A936CF2F90CD41B14 /* DictionaryTransform.swift */, + F6016CF43C0B2D31043ADD65889FBB42 /* EnumOperators.swift */, + 6FE948AF72E43DA87B86E6EE34844AA7 /* EnumTransform.swift */, + 6D31C620E17F575E6E2F90BC9D2A29AC /* FromJSON.swift */, + 7CA95DDF2A57AADC3E6B6647C6A5F39F /* HexColorTransform.swift */, + 47804D2377F9E25533891D9B9C72C58A /* ImmutableMappable.swift */, + D2CDCE9F4E104ACC626EEEF1A601E4CD /* IntegerOperators.swift */, + 4E1D705189D79F699FF674088C380272 /* ISO8601DateTransform.swift */, + 3E40BD236BFB5823682FB0FE1E7E15BD /* Map.swift */, + 87E6C9F2F10891B6C1D7116A2E3CD8B9 /* MapError.swift */, + F2DE6CE475EA18FEECF0A57C67576A88 /* Mappable.swift */, + F8548C09A1A91E9A78E396912E7341AC /* Mapper.swift */, + 3C1D01AEBA8A6116CA91054054C4EC1E /* NSDecimalNumberTransform.swift */, + AAEBB50390AA61AD781599F0627E4C4B /* Operators.swift */, + 41CE0E198552CF07557A00D4F80C0F36 /* ToJSON.swift */, + 491E3482FFE9D75092E0FD00A4E2C144 /* TransformOf.swift */, + 47CD592978CC4B92452ADA4ABBAB4803 /* TransformOperators.swift */, + 6B5EC70BFF0AB9EE7D13152B0E1ABE1C /* TransformType.swift */, + 67340A7EFCE654D4C23EAF007F66C19E /* URLTransform.swift */, + 8A66F46EDBAC17B079E406AE67924FC5 /* Support Files */, + ); + path = ObjectMapper; + sourceTree = ""; + }; + FD2E5414938C5E6992A842FFCCF24745 /* Products */ = { + isa = PBXGroup; + children = ( + 966AA42878212207687E9A2A4DBCD618 /* Alamofire.framework */, + 43DA6DFAA898F949ACBD91D709EF13F8 /* Alamofire.framework */, + 83403244CDF477D6E50171D9E3F24ABA /* AlamofireObjectMapper.framework */, + 01CB31E026580CB87518E18B1B4E832D /* AlamofireObjectMapper.framework */, + 5149F2ED76FF28D39794B30B6B89D8E4 /* CryptoSwift.framework */, + 0D082F4E7BF859609078D00BDE67D297 /* CryptoSwift.framework */, + 3B1A445A57C6FE99F504F8D345940BEA /* ObjectMapper.framework */, + 72E2B6C6AAA2FC3B536F80138DBFD0A1 /* ObjectMapper.framework */, + 01EC8D9B4A54CA713CAB406F17C2E5D2 /* Pods_BSRadioWaves.framework */, + C1A3FAEEE74C5DD88B7F36BB5F750427 /* Pods_Watch_Extension.framework */, + CFF06E53BC38C0114EDAF51F6C433D9F /* SDWebImage.framework */, + 29F95D207B77C866435357C8CCAB387B /* SDWebImage.framework */, + D6043471C96F93DC41F7DD1E0D7D8B35 /* Toast_Swift.framework */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 1DA17A25544C4728D4BD212A7394986A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + C581285B8AB6D47A2BBC0F1FB0436437 /* Alamofire-iOS-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4799AA530EFA756E9556DEB78EBEC8CC /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 5A4410AFFAE7F5039CC9161F49C04038 /* AlamofireObjectMapper-iOS-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 541A0721D8D26374CF7CF04B1473A45A /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 2024EE5E265681137A9FEBC630E6E0F1 /* Toast-Swift-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 668AB70724B6E0E92452CE9E35E6F054 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + D647AC1C09248E9D70678AD2C9AB7082 /* AlamofireObjectMapper-watchOS-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 924E5478006A87D5E13941CCB12BA3F9 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 016D4F6D0512E0659937DB5D9A7C5384 /* Alamofire-watchOS-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A105AE9E9BA69891D79B6EF0F0D2779F /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + BA216F9064812FB41D691FC6F06EEBA8 /* CryptoSwift-iOS-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + A2428F5CD1D091288248DA2773081EC7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 84110DCD323D8B02BDD58AC4783A372E /* ObjectMapper-iOS-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CD2223A5B639FEB583580615A9C8F2E7 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 11BA51468C6BEBB50D3B42D5DD0DB2FE /* NSButton+WebCache.h in Headers */, + 5706F9D06ADDDD84552008140D8D3230 /* NSData+ImageContentType.h in Headers */, + 6DA6EEC44EB98C02ED794A90A0AF255E /* NSImage+WebCache.h in Headers */, + 611AB64AB4C84F5F8E2380A43345E351 /* SDAnimatedImageRep.h in Headers */, + 19DC365B1810400A707E80F25800CE2F /* SDImageCache.h in Headers */, + B172ED0AC453B91CDE97CD7EFAA5B143 /* SDImageCacheConfig.h in Headers */, + 4C9D0AB942C6B5C2DF95B3A4E2EEE9EC /* SDWebImage-watchOS-umbrella.h in Headers */, + E034E406CEA11CB9D4D3DCE9400EF957 /* SDWebImageCoder.h in Headers */, + F1DB4730A8DE6E59EED9E2B60F3F1EC8 /* SDWebImageCoderHelper.h in Headers */, + 07A83E7FDC67DC07531437F3B2429F9C /* SDWebImageCodersManager.h in Headers */, + 8F5EA601325668BE77836C2E2491F5A5 /* SDWebImageCompat.h in Headers */, + 617A4B2BC36A71E862EB0C8A93990120 /* SDWebImageDownloader.h in Headers */, + 6F1B74372FC3AA7C6C98671039F6BA49 /* SDWebImageDownloaderOperation.h in Headers */, + 4416B6EF81FA316E311A2CB14A750E59 /* SDWebImageFrame.h in Headers */, + EE45C83BE8BEE144D0FDE1C4C552E12A /* SDWebImageGIFCoder.h in Headers */, + 49B7962FEEB34E5815E36EB7BDEC705B /* SDWebImageImageIOCoder.h in Headers */, + ABF48D749FC078372C89F3D6EE80A1DA /* SDWebImageManager.h in Headers */, + E3C0F0871B18438048CE5C9C51F71E35 /* SDWebImageOperation.h in Headers */, + 8E8CA6B26DE8101725A2CE5700E82A26 /* SDWebImagePrefetcher.h in Headers */, + 98C94873E547AAD3BC4AA1F4D3EB2FF1 /* SDWebImageTransition.h in Headers */, + 5EB2768C011DE9C8FE837773AA73CD07 /* UIButton+WebCache.h in Headers */, + 60EA59B5146F9FB15AAFF20FF32387B0 /* UIImage+ForceDecode.h in Headers */, + 96288FBB89EE8E87DE4AB79350B95D31 /* UIImage+GIF.h in Headers */, + 676E149D31AF6FCB7C7AE88825D88B55 /* UIImage+MemoryCacheCost.h in Headers */, + 952B55A2A89F29F246568BC14E5F7245 /* UIImage+MultiFormat.h in Headers */, + 3722ACD41FB5DC82551D8C9D67913A6B /* UIImageView+HighlightedWebCache.h in Headers */, + 1969B263630CA265C10336D7BA1FAB3E /* UIImageView+WebCache.h in Headers */, + C23B248793952A4857145A3A869A68A9 /* UIView+WebCache.h in Headers */, + 968D99188F43BC53E16A9A4B8A0F2EDC /* UIView+WebCacheOperation.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E2796F732FEFFB709CA3ACEBB308B196 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + CFEF2C7F05632F2E54E2381DE8306D68 /* Pods-Watch Extension-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E9CA2EEA4EFCF69AD6C637D64212E4D4 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + CD215AE8FB5D1B3EF3D4B04AE47C0BF4 /* NSButton+WebCache.h in Headers */, + 67554580402C7300A860AF9563FC3A6F /* NSData+ImageContentType.h in Headers */, + D17C3FD8E125B305C71FE2DDF9177365 /* NSImage+WebCache.h in Headers */, + 3C32046F5D649BFBABD868F717EBFDCD /* SDAnimatedImageRep.h in Headers */, + FBBB16BB9F3574C263332B3D6ABED1A7 /* SDImageCache.h in Headers */, + 2A6384DF808EF5DEACF2BEDE85DE1122 /* SDImageCacheConfig.h in Headers */, + EEF53A9F65D755A52D2CFDC8ED1058B3 /* SDWebImage-iOS-umbrella.h in Headers */, + 67F01BB8E113750A7C0DA9E918D8D57D /* SDWebImageCoder.h in Headers */, + 351C9E0999DBBD3039305453571B4CAF /* SDWebImageCoderHelper.h in Headers */, + 55FB3669E7D1C8B5C8DA456E4C568E8B /* SDWebImageCodersManager.h in Headers */, + 4453055474E17318AAEB2334C7667B92 /* SDWebImageCompat.h in Headers */, + 98B68DD45987E99FB68542776889FC17 /* SDWebImageDownloader.h in Headers */, + BA9ED09E5C5C7485AC1A8573DAB5CE82 /* SDWebImageDownloaderOperation.h in Headers */, + E8AAD097E6F3BD0C9B8A13B63D402493 /* SDWebImageFrame.h in Headers */, + C7ABC1A7419640A1072B50D86EA569A7 /* SDWebImageGIFCoder.h in Headers */, + 99C1A41C9D214EA1BE189149F0F53275 /* SDWebImageImageIOCoder.h in Headers */, + E817D6A4B21742A4AB91330BC605A53B /* SDWebImageManager.h in Headers */, + E4DCB1B21E77C670085A051143CD9E66 /* SDWebImageOperation.h in Headers */, + C41D774CB57D4E34CB54B69BA27CE44E /* SDWebImagePrefetcher.h in Headers */, + 3D7620A75375E0E74DDAB0981BAEB064 /* SDWebImageTransition.h in Headers */, + 2EF5A6F5A7BEB727E439F7D8644A91A8 /* UIButton+WebCache.h in Headers */, + 083C363C26AA6B89D057D3D78964FB5E /* UIImage+ForceDecode.h in Headers */, + 7C266B5B99C315500567C5E092B90833 /* UIImage+GIF.h in Headers */, + F5202BB39510DE07DEB984BA640F2008 /* UIImage+MemoryCacheCost.h in Headers */, + 2639C366DD45C5C06CA83D99DBAA39E7 /* UIImage+MultiFormat.h in Headers */, + 00271C40AF1CFB935EC252DC984E552D /* UIImageView+HighlightedWebCache.h in Headers */, + C964F6A2C51B36C12124F2FC45A8F774 /* UIImageView+WebCache.h in Headers */, + B1BF52B1EE2B1A9A0737B408C040DC50 /* UIView+WebCache.h in Headers */, + 78B8F270B43ABF2D7BC5A7683A8A2AB8 /* UIView+WebCacheOperation.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EA5131D1DCEF88644DF7650BC7CD04B0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E6F1A0D418690C97ADD49EDAA3897E5 /* Pods-BSRadioWaves-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + EAE4A7CF264842A9C904B8F4967AD664 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E372E2A2A5FD43A01E4D3059AEF97F9C /* CryptoSwift-watchOS-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F5CEA2AD87C9B4540CCE826E44F6FA13 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + E8E65396A4375B8F50714A5BE658E557 /* ObjectMapper-watchOS-umbrella.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 218BFCBCA0EA83AEA95CE87303914A04 /* CryptoSwift-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8005A8EEDAB9F7878D1828CE167C4F68 /* Build configuration list for PBXNativeTarget "CryptoSwift-iOS" */; + buildPhases = ( + A105AE9E9BA69891D79B6EF0F0D2779F /* Headers */, + 974E16DE8E529288B187D5325D2CB7E1 /* Sources */, + 167A0432F4E911437466D3A9AD3EEBD5 /* Frameworks */, + B33FE805C87DC4C6640226CA59D202D5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "CryptoSwift-iOS"; + productName = "CryptoSwift-iOS"; + productReference = 5149F2ED76FF28D39794B30B6B89D8E4 /* CryptoSwift.framework */; + productType = "com.apple.product-type.framework"; + }; + 2DD7340C090E11B5F0EE3D8F6DB08E6B /* Pods-Watch Extension */ = { + isa = PBXNativeTarget; + buildConfigurationList = 28EC073B2BB88BD95A70D724104E5021 /* Build configuration list for PBXNativeTarget "Pods-Watch Extension" */; + buildPhases = ( + E2796F732FEFFB709CA3ACEBB308B196 /* Headers */, + 859DA4A527C0326C3D5419DD708D65DD /* Sources */, + E602E9FC4404EA63875018424E0FBD68 /* Frameworks */, + 257664362CF9F8DD6BEE82F52B58DA35 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 3CCEA9B51C6A5BEB7EB7732442C69DEA /* PBXTargetDependency */, + 899926C8C99AB48DFF1F940D4FF16612 /* PBXTargetDependency */, + 34F0B85E8BA3D68B14296C04D5D492A6 /* PBXTargetDependency */, + C05BB58C6B789082AE34C92160E64E23 /* PBXTargetDependency */, + 1507F591A681CFA06E38090281E33383 /* PBXTargetDependency */, + ); + name = "Pods-Watch Extension"; + productName = "Pods-Watch Extension"; + productReference = C1A3FAEEE74C5DD88B7F36BB5F750427 /* Pods_Watch_Extension.framework */; + productType = "com.apple.product-type.framework"; + }; + 2FD806DB695223C0672239A9FE30B913 /* CryptoSwift-watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7F7B1A606984012F6CCE51C309204FBC /* Build configuration list for PBXNativeTarget "CryptoSwift-watchOS" */; + buildPhases = ( + EAE4A7CF264842A9C904B8F4967AD664 /* Headers */, + 51307CA679B639C3FC4510D73B628FB3 /* Sources */, + 04B4849F1FFDB6B2A1089C928FB7BC0C /* Frameworks */, + E84412117D364906FF39DE53950B9289 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "CryptoSwift-watchOS"; + productName = "CryptoSwift-watchOS"; + productReference = 0D082F4E7BF859609078D00BDE67D297 /* CryptoSwift.framework */; + productType = "com.apple.product-type.framework"; + }; + 6447A5D6B2905FE6A09B0ABC0042EC50 /* SDWebImage-watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = C8E8FF18B09E22C119FDC1766EDCA98E /* Build configuration list for PBXNativeTarget "SDWebImage-watchOS" */; + buildPhases = ( + CD2223A5B639FEB583580615A9C8F2E7 /* Headers */, + 2613FDB7A0227571C4335E5752F712FA /* Sources */, + F207463F944742D651704A02BA815208 /* Frameworks */, + 45F90FAF50D1AAD68C5B1F940E59AA93 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SDWebImage-watchOS"; + productName = "SDWebImage-watchOS"; + productReference = 29F95D207B77C866435357C8CCAB387B /* SDWebImage.framework */; + productType = "com.apple.product-type.framework"; + }; + 66F51BC925FD5FB829E8D422C690BDF0 /* Alamofire-watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = E61069F691B31002ED13C26F610A6144 /* Build configuration list for PBXNativeTarget "Alamofire-watchOS" */; + buildPhases = ( + 924E5478006A87D5E13941CCB12BA3F9 /* Headers */, + 4F26B3D9FD1CB8F709BE24709C1C79B5 /* Sources */, + 152219B0468DDEDC15A7E8759DF2FB2F /* Frameworks */, + F98B8366BD5F971AECCBE2D0B878D65B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Alamofire-watchOS"; + productName = "Alamofire-watchOS"; + productReference = 43DA6DFAA898F949ACBD91D709EF13F8 /* Alamofire.framework */; + productType = "com.apple.product-type.framework"; + }; + 739D23BF96457378860369EA2DA315C9 /* AlamofireObjectMapper-watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 53A55F5440CDA2072D66FB8102A72827 /* Build configuration list for PBXNativeTarget "AlamofireObjectMapper-watchOS" */; + buildPhases = ( + 668AB70724B6E0E92452CE9E35E6F054 /* Headers */, + 88E323CF228A17E09E87BE3A0B1626C2 /* Sources */, + 366BAEF20D927232D8C36EB300DE337D /* Frameworks */, + C5012CE9641BFFBB01102C36160B8315 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 9A3E4F97EBA370D28EF1E42929233CC1 /* PBXTargetDependency */, + 505E5A61DFD0EAAA199C9E9563624FB2 /* PBXTargetDependency */, + ); + name = "AlamofireObjectMapper-watchOS"; + productName = "AlamofireObjectMapper-watchOS"; + productReference = 01CB31E026580CB87518E18B1B4E832D /* AlamofireObjectMapper.framework */; + productType = "com.apple.product-type.framework"; + }; + 744F52F389060600FE79F1B9A709C630 /* SDWebImage-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = FA578CEFC64D098EA954DA0C3584D935 /* Build configuration list for PBXNativeTarget "SDWebImage-iOS" */; + buildPhases = ( + E9CA2EEA4EFCF69AD6C637D64212E4D4 /* Headers */, + 07879F68B777A8E94586A981EB906618 /* Sources */, + DAFDF3E5D36B5892FDFE65BB75AF9ABB /* Frameworks */, + 6CE99D492322E6107E6A9778E42F5099 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SDWebImage-iOS"; + productName = "SDWebImage-iOS"; + productReference = CFF06E53BC38C0114EDAF51F6C433D9F /* SDWebImage.framework */; + productType = "com.apple.product-type.framework"; + }; + 77F4321EB2A71321DE0D59BDF4C62E3F /* ObjectMapper-watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = D45F63E4A3CBD4DDABC72806CC0FAD29 /* Build configuration list for PBXNativeTarget "ObjectMapper-watchOS" */; + buildPhases = ( + F5CEA2AD87C9B4540CCE826E44F6FA13 /* Headers */, + B789942D8246A09D6E58D91FDC0BDD72 /* Sources */, + 80CC111D5A09EBD3E97F6D9B4F66B40C /* Frameworks */, + 91BAC884368F2FF4AECFFA937746978E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "ObjectMapper-watchOS"; + productName = "ObjectMapper-watchOS"; + productReference = 72E2B6C6AAA2FC3B536F80138DBFD0A1 /* ObjectMapper.framework */; + productType = "com.apple.product-type.framework"; + }; + 7B450F2E8D53215597AEE594BA0BB14B /* AlamofireObjectMapper-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = BA5FCF9126572083B3E946EC76DD8512 /* Build configuration list for PBXNativeTarget "AlamofireObjectMapper-iOS" */; + buildPhases = ( + 4799AA530EFA756E9556DEB78EBEC8CC /* Headers */, + 3F3EF6D2CBAC43AA7E6DD656E875DDAB /* Sources */, + 3D4F61692D905FF0934E576DDF5C775E /* Frameworks */, + 3A88FFC4F8AE7B599F7E5279445DF8F1 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 32557E8D9DF53089C05A72A2DC94659F /* PBXTargetDependency */, + 77FC4B82915BFDB6ECEF301D2D21E02B /* PBXTargetDependency */, + ); + name = "AlamofireObjectMapper-iOS"; + productName = "AlamofireObjectMapper-iOS"; + productReference = 83403244CDF477D6E50171D9E3F24ABA /* AlamofireObjectMapper.framework */; + productType = "com.apple.product-type.framework"; + }; + B990BD87169C76A3ED3FE8A9258D91A3 /* Toast-Swift */ = { + isa = PBXNativeTarget; + buildConfigurationList = B8C401847A53B4C2810311A8CBD715AD /* Build configuration list for PBXNativeTarget "Toast-Swift" */; + buildPhases = ( + 541A0721D8D26374CF7CF04B1473A45A /* Headers */, + 32133C6B0EACD421CB9EB1ABFCE89B97 /* Sources */, + 6102CF7EA55F5A7D669F88BF0D1A701F /* Frameworks */, + 8812DCC289D1E7BE07818E350A3B8656 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Toast-Swift"; + productName = "Toast-Swift"; + productReference = D6043471C96F93DC41F7DD1E0D7D8B35 /* Toast_Swift.framework */; + productType = "com.apple.product-type.framework"; + }; + D01A02B225FD29F76E911D60DBFD443C /* ObjectMapper-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = AB249E6B9302267A487C5B3C2CDEE10E /* Build configuration list for PBXNativeTarget "ObjectMapper-iOS" */; + buildPhases = ( + A2428F5CD1D091288248DA2773081EC7 /* Headers */, + 8E7F8866EBFEE36995355437396282BE /* Sources */, + 1D05D89C7E09239776CE173343A5EEDD /* Frameworks */, + 73FBB87D046D2A497B4DDB02E2E6E167 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "ObjectMapper-iOS"; + productName = "ObjectMapper-iOS"; + productReference = 3B1A445A57C6FE99F504F8D345940BEA /* ObjectMapper.framework */; + productType = "com.apple.product-type.framework"; + }; + FD8828BFC368157226E204A32CD5B6DE /* Alamofire-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = E65E740C96442990E6E9CDF05EE3EFEF /* Build configuration list for PBXNativeTarget "Alamofire-iOS" */; + buildPhases = ( + 1DA17A25544C4728D4BD212A7394986A /* Headers */, + 22F0F0797A0F8589B712179A239E44F0 /* Sources */, + 51C49E6511B1FE5314E69AD783B2DF18 /* Frameworks */, + C3F35C916725EA4118F0150CF661682F /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Alamofire-iOS"; + productName = "Alamofire-iOS"; + productReference = 966AA42878212207687E9A2A4DBCD618 /* Alamofire.framework */; + productType = "com.apple.product-type.framework"; + }; + FFE2BA509A042A5CD356CFF9A979EFFD /* Pods-BSRadioWaves */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8D0F46248CC8E71F9C2CDB6D55831EA4 /* Build configuration list for PBXNativeTarget "Pods-BSRadioWaves" */; + buildPhases = ( + EA5131D1DCEF88644DF7650BC7CD04B0 /* Headers */, + B18779B2D274BA5E6E71E6E021C699DF /* Sources */, + AF03E7B12542EB9BB4E6BE5E2056ABC0 /* Frameworks */, + C99ED039FC023ABAE2D70A8D8560C73D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ED8C926256AC2BB881CEDD40E826AA01 /* PBXTargetDependency */, + FB919FA21E1BAC9083AC1E0A7F4E05FD /* PBXTargetDependency */, + 255502416A4E946183035BBAF81BB38B /* PBXTargetDependency */, + 7416035C3BE41EE17E3D2CF8A3F0F66A /* PBXTargetDependency */, + 41B08F091A3DC9DB9D83A6D8E371577F /* PBXTargetDependency */, + AD80CD311D364F8A33C0BF5402CA6D12 /* PBXTargetDependency */, + ); + name = "Pods-BSRadioWaves"; + productName = "Pods-BSRadioWaves"; + productReference = 01EC8D9B4A54CA713CAB406F17C2E5D2 /* Pods_BSRadioWaves.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BFDFE7DC352907FC980B868725387E98 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1100; + LastUpgradeCheck = 1100; + }; + buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = CF1408CF629C7361332E53B88F7BD30C; + productRefGroup = FD2E5414938C5E6992A842FFCCF24745 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + FD8828BFC368157226E204A32CD5B6DE /* Alamofire-iOS */, + 66F51BC925FD5FB829E8D422C690BDF0 /* Alamofire-watchOS */, + 7B450F2E8D53215597AEE594BA0BB14B /* AlamofireObjectMapper-iOS */, + 739D23BF96457378860369EA2DA315C9 /* AlamofireObjectMapper-watchOS */, + 218BFCBCA0EA83AEA95CE87303914A04 /* CryptoSwift-iOS */, + 2FD806DB695223C0672239A9FE30B913 /* CryptoSwift-watchOS */, + D01A02B225FD29F76E911D60DBFD443C /* ObjectMapper-iOS */, + 77F4321EB2A71321DE0D59BDF4C62E3F /* ObjectMapper-watchOS */, + FFE2BA509A042A5CD356CFF9A979EFFD /* Pods-BSRadioWaves */, + 2DD7340C090E11B5F0EE3D8F6DB08E6B /* Pods-Watch Extension */, + 744F52F389060600FE79F1B9A709C630 /* SDWebImage-iOS */, + 6447A5D6B2905FE6A09B0ABC0042EC50 /* SDWebImage-watchOS */, + B990BD87169C76A3ED3FE8A9258D91A3 /* Toast-Swift */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 257664362CF9F8DD6BEE82F52B58DA35 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3A88FFC4F8AE7B599F7E5279445DF8F1 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 45F90FAF50D1AAD68C5B1F940E59AA93 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 6CE99D492322E6107E6A9778E42F5099 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 73FBB87D046D2A497B4DDB02E2E6E167 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8812DCC289D1E7BE07818E350A3B8656 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 91BAC884368F2FF4AECFFA937746978E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B33FE805C87DC4C6640226CA59D202D5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C3F35C916725EA4118F0150CF661682F /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C5012CE9641BFFBB01102C36160B8315 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C99ED039FC023ABAE2D70A8D8560C73D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + E84412117D364906FF39DE53950B9289 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F98B8366BD5F971AECCBE2D0B878D65B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 07879F68B777A8E94586A981EB906618 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CD1E6265FDE55BFF1CA691437CBF8398 /* NSButton+WebCache.m in Sources */, + B96E48C00BD5DD0E42F7AC38903FC514 /* NSData+ImageContentType.m in Sources */, + 40513DA063AEC8135574BCD3C651DD94 /* NSImage+WebCache.m in Sources */, + 59AC5DB9C43DA74449B73E06F10AF537 /* SDAnimatedImageRep.m in Sources */, + 183F3DD9433855E6E8BD250389AF5490 /* SDImageCache.m in Sources */, + 22B974F6D8AE91C7EBB281BA295BFDED /* SDImageCacheConfig.m in Sources */, + E7172B475D62C28BEF8E044C7243D65D /* SDWebImage-iOS-dummy.m in Sources */, + AA18263C63CD5F1F592297D6772E212E /* SDWebImageCoder.m in Sources */, + 71B626C86FFD955C154A3BC3327215E3 /* SDWebImageCoderHelper.m in Sources */, + 777BFFAE705CE49B0B906D15FF00AC7C /* SDWebImageCodersManager.m in Sources */, + F583AEF68EAC42313F3CDDAE6AACA9FF /* SDWebImageCompat.m in Sources */, + 84FB085C8CD5330D49B62BA15469712D /* SDWebImageDownloader.m in Sources */, + FB967296A5EF6F11F3C80E0579A4FF2C /* SDWebImageDownloaderOperation.m in Sources */, + 534CE6051A9CB5086D6A19383738EE5A /* SDWebImageFrame.m in Sources */, + DD50BC31EFA8E65EC871E8AC986E037F /* SDWebImageGIFCoder.m in Sources */, + 1DD06E247F72CDCFFA1AEEF11F5087CA /* SDWebImageImageIOCoder.m in Sources */, + 82BA89811E67B211A5BC1F2902F0A40F /* SDWebImageManager.m in Sources */, + 5DF7A8F8D41D428EB9BBFA6BB3A45FC2 /* SDWebImagePrefetcher.m in Sources */, + 7943B85076F29D747D2E499C2EE6A811 /* SDWebImageTransition.m in Sources */, + D4840B434912B55E6AF0E57E006D5A77 /* UIButton+WebCache.m in Sources */, + 0D1CFE37DDE9FA2C68AA4732ABEC59F9 /* UIImage+ForceDecode.m in Sources */, + A8C6E353DBCC0D1D34847D267AB7EF61 /* UIImage+GIF.m in Sources */, + C6347B8872EEC1A20EBA03B1C8CB4AE4 /* UIImage+MemoryCacheCost.m in Sources */, + 6F3D4FFD473B6D7EFE13688F9679E266 /* UIImage+MultiFormat.m in Sources */, + F0B6D1AF9B9BD8DE4403C30A9A93E5DE /* UIImageView+HighlightedWebCache.m in Sources */, + 4208B4C5B873E595AB329242ED1E4DC4 /* UIImageView+WebCache.m in Sources */, + 1ED564129D44BA0F9377E0576E1E859B /* UIView+WebCache.m in Sources */, + 843E862D6232E2617C20FE72CAFC28AB /* UIView+WebCacheOperation.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 22F0F0797A0F8589B712179A239E44F0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 456F5AB16DE22E601CA5EB4200088DD0 /* AFError.swift in Sources */, + 912A476FD85EECC920A508E12460EFB8 /* Alamofire-iOS-dummy.m in Sources */, + 4CE4A9C57F0DE9DF2CF65F63D68B6FEB /* Alamofire.swift in Sources */, + 670AB4D559C4E66CF0B60B27C0DE2646 /* DispatchQueue+Alamofire.swift in Sources */, + 13D4ACAB3F0392D7263702403F4C4C77 /* MultipartFormData.swift in Sources */, + AFA9BCA194B0E1ABFDED55E02B3153F5 /* NetworkReachabilityManager.swift in Sources */, + F2884C16786810D1B40F39DAFBCF4303 /* Notifications.swift in Sources */, + 0BD66FAA67A327E7DDD184F40EC99076 /* ParameterEncoding.swift in Sources */, + 91D45871DE32A3C1B2E845F54E9A2660 /* Request.swift in Sources */, + 9A0D8180A8542BD19E2AEF533626FD32 /* Response.swift in Sources */, + E9478B9C29741BB15C26529B33AD798D /* ResponseSerialization.swift in Sources */, + 546323B71CA763DE815B4955EE3F2064 /* Result.swift in Sources */, + EE822282C912F20733663B0E9FAEAD6B /* ServerTrustPolicy.swift in Sources */, + 3AB990FDF4FCA4090651180F1325B815 /* SessionDelegate.swift in Sources */, + A3007EA32DCAB1CA67795414671FF618 /* SessionManager.swift in Sources */, + 01CAEC5F6F9431E4D251A35A36F6A9EE /* TaskDelegate.swift in Sources */, + 82C72B35091073596FE61D069FFB8A80 /* Timeline.swift in Sources */, + 98EB0914754838B056FC2410E28436A1 /* Validation.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 2613FDB7A0227571C4335E5752F712FA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 251092C90608B134761700CA7A7C9B72 /* NSButton+WebCache.m in Sources */, + 04B00E068A79A5DD6B0485F38928B785 /* NSData+ImageContentType.m in Sources */, + 9989104278D65E6AEF8BD0E65CC17251 /* NSImage+WebCache.m in Sources */, + 670E976777CE44A3F4BF59950C2055DB /* SDAnimatedImageRep.m in Sources */, + 85C0440106C1A7A7DDB935EE24248EF7 /* SDImageCache.m in Sources */, + 7D66B93BAB2738CEB4FF21C160082B9B /* SDImageCacheConfig.m in Sources */, + 845B829CF7011A308F9558751334CB9E /* SDWebImage-watchOS-dummy.m in Sources */, + B2125307524BEAF53AC64600862ADF4C /* SDWebImageCoder.m in Sources */, + D41C1FFD88013EDE76C8DF9BCD1A241A /* SDWebImageCoderHelper.m in Sources */, + 33BB727FB0183B19924B416F1D002EA3 /* SDWebImageCodersManager.m in Sources */, + 1F1FDA2C0DCBA6DB3151DA3213DE53C8 /* SDWebImageCompat.m in Sources */, + 7BB18C59ABE36E32FFCCFC99CB0FD4FA /* SDWebImageDownloader.m in Sources */, + 149A8E4C500AC240AFA3375ACEC6D739 /* SDWebImageDownloaderOperation.m in Sources */, + 3D468C0815E3A6AD6CA5D1FF6888AAEB /* SDWebImageFrame.m in Sources */, + B7BB5A1A61BA555178810C0A916B04BD /* SDWebImageGIFCoder.m in Sources */, + E0FDBFAC8A133626CDCEF45E0F620FBA /* SDWebImageImageIOCoder.m in Sources */, + 081919834624DA9CC57286E7058729C9 /* SDWebImageManager.m in Sources */, + 7840564DDAB7AB3396808E321E51D882 /* SDWebImagePrefetcher.m in Sources */, + DD30892CAFD4402BD8E2282DC1EE3877 /* SDWebImageTransition.m in Sources */, + 38FB0E7C2F07D0640CA816C3E4E7F740 /* UIButton+WebCache.m in Sources */, + 52238EC162F664F6A4E5D1E744C6BFCF /* UIImage+ForceDecode.m in Sources */, + 8B1E87732D0D5158122E5514CB8E6010 /* UIImage+GIF.m in Sources */, + 7738227A14449B8ED4758B8621F4BD28 /* UIImage+MemoryCacheCost.m in Sources */, + 5CB34F05FD5BA8236759368A58008493 /* UIImage+MultiFormat.m in Sources */, + BC7C2C97510030284CF6E97FCBD45A35 /* UIImageView+HighlightedWebCache.m in Sources */, + D18B66F656E0C735974BFDC5C56F5FD6 /* UIImageView+WebCache.m in Sources */, + D9A3D5DE6A8CF2DD3EB35A030F200E5E /* UIView+WebCache.m in Sources */, + 0E95F909D3EC1C4EE448A9C78DFA7DCF /* UIView+WebCacheOperation.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 32133C6B0EACD421CB9EB1ABFCE89B97 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6B326644BB08AEDF697A82A0F1A66D68 /* Toast-Swift-dummy.m in Sources */, + 4753716AE7A1AB22FB6BA61AA74D942F /* Toast.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 3F3EF6D2CBAC43AA7E6DD656E875DDAB /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FC323405C3A2FCC9514FC8A68CEF8580 /* AlamofireObjectMapper-iOS-dummy.m in Sources */, + F31AFD9C51489632A37CEA5705D55BE6 /* AlamofireObjectMapper.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4F26B3D9FD1CB8F709BE24709C1C79B5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A4CAA381B50248056BDFB9AFBD8867C9 /* AFError.swift in Sources */, + B4475FE96A5EB06ABC96CEA377C62B0C /* Alamofire-watchOS-dummy.m in Sources */, + 2F3A7727F25809D20B4D5115D64F545A /* Alamofire.swift in Sources */, + FF0835B3ECDED1DE76455DE10A228B58 /* DispatchQueue+Alamofire.swift in Sources */, + E0DF3A0ED5FAA2FE0C1E2396CBC4F968 /* MultipartFormData.swift in Sources */, + E2F9BFECBBEBDF515A49318C8AF36D74 /* NetworkReachabilityManager.swift in Sources */, + A0E1AFB4104DD8C24BA35979E670F51F /* Notifications.swift in Sources */, + C7E530B3A0405BD8B338F9D3DB0978C8 /* ParameterEncoding.swift in Sources */, + 0281DB230A246653CBFC06716D26833C /* Request.swift in Sources */, + 495FE1474EB2181D16F1D6BCAB1CF2C6 /* Response.swift in Sources */, + 0F7BDECDD56B33D440AE53E632594FA2 /* ResponseSerialization.swift in Sources */, + F197A795CA0D500CCA5351183EDAF6BD /* Result.swift in Sources */, + 5DC223206D9E0964E6D1E700896661BC /* ServerTrustPolicy.swift in Sources */, + C6B9E73B20C867D11C52F1FF43D1908B /* SessionDelegate.swift in Sources */, + 451FB27A7555760099E5B2C1AF2844C3 /* SessionManager.swift in Sources */, + 9710AA8455D26EB1E65EC48EB73662E5 /* TaskDelegate.swift in Sources */, + EA2DA37B7ED37959847875D89F6D3271 /* Timeline.swift in Sources */, + 4C83C1F54714ACFB4B695E513A2BB1B3 /* Validation.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 51307CA679B639C3FC4510D73B628FB3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 098072C1CC99DE5810FE1609F1FF3F15 /* AEAD.swift in Sources */, + 0531358ED3EEA7DA09D4A1434463D3BD /* AEADChaCha20Poly1305.swift in Sources */, + 3AF5A66E94A640FE0D7F5A8E4791FF0B /* AES+Foundation.swift in Sources */, + EA1EAB31972EC3579B31C8A7083351D9 /* AES.Cryptors.swift in Sources */, + 69D3DD7100C6F6572F8750F383B18F6B /* AES.swift in Sources */, + 75DB763A45F389C7A22038E611D2DA85 /* Array+Extension.swift in Sources */, + EE217BC1DA5EDDDC645CF1CA2E532EE6 /* Array+Foundation.swift in Sources */, + 98A2AC4BCD9E2B757847828E9C5F1F82 /* Authenticator.swift in Sources */, + B5E09D67C012F834056AC332C7C30363 /* BatchedCollection.swift in Sources */, + 2796A50CEB957A8B6F87FFB1F5144873 /* Bit.swift in Sources */, + 158A572BA530B879969A463DAC72E471 /* BlockCipher.swift in Sources */, + 5839BD02D33AEEDD6B9D1BF39B2F8D9E /* BlockDecryptor.swift in Sources */, + 6CB2C8A094A3B452C6BFC8E2999DDAA7 /* BlockEncryptor.swift in Sources */, + 95924A7F08FFDA37D0E07330585B0F7C /* BlockMode.swift in Sources */, + 266520AC43ED9DF12A683A99F5E9C3E5 /* BlockModeOptions.swift in Sources */, + 4D220E8AB887166036114C207C23EB27 /* Blowfish+Foundation.swift in Sources */, + B51460CAD56A2ECF0E246A5AD5F4D66D /* Blowfish.swift in Sources */, + 4682F8666DB6D570CBFE49E9E853B21A /* CBC.swift in Sources */, + 555CCE7489DCA14A8820185B1112D9A9 /* CBCMAC.swift in Sources */, + F02FC1BB9AE21AB8A44ED989820240B1 /* CCM.swift in Sources */, + 61436F06ECBFF3AA5F51E4146ACDF7FE /* CFB.swift in Sources */, + 85E60A68EFBC58B96FAE3BAC44F578C4 /* ChaCha20+Foundation.swift in Sources */, + 0CD7DB3813871C92BC9A4D2257548455 /* ChaCha20.swift in Sources */, + C7DFBFA2EC8D8C2491FEE96F274F65DD /* Checksum.swift in Sources */, + 3C824072FCB242031FCE0F0DF2DB9A59 /* Cipher.swift in Sources */, + A10EE5EFCCDC8466FA0154AA9DFB3737 /* CipherModeWorker.swift in Sources */, + BBE2ABFFA12B206F9C07615EF7BAF6D0 /* CMAC.swift in Sources */, + 5088A386549E488BF0877FE6A4BB2FAA /* Collection+Extension.swift in Sources */, + 5CBB7CEC836EF2FF32D704C54CDAB879 /* CompactMap.swift in Sources */, + F521AAF77D40DBF1080A4D020D8AA436 /* Cryptor.swift in Sources */, + 77A5A8CE350CAEA3C22B6AF11D049A57 /* Cryptors.swift in Sources */, + 3D02F66096398ED3952DFDD526A4A6F9 /* CryptoSwift-watchOS-dummy.m in Sources */, + 52EBC9A20D621DC61F5EC609E18A2A95 /* CTR.swift in Sources */, + A1BEDFE18055DC04EE59115BEB931F1E /* Data+Extension.swift in Sources */, + 4000B140B0CEC176DCBFEED2F111D340 /* Digest.swift in Sources */, + BD3C3F8B2BAB2D9D8613152D804CEAC9 /* DigestType.swift in Sources */, + 4628A632B1ED82AD170EAE18F83D6B5E /* ECB.swift in Sources */, + B6775198FDCC82EB570DDCED95B912A1 /* GCM.swift in Sources */, + 44B648F9466A039EA185A9B435330884 /* Generics.swift in Sources */, + 471E0B5164CFD1AE905CE8624DCBCAA8 /* HKDF.swift in Sources */, + 6144D447A7DAD552A07FE7F2EE5DB664 /* HMAC+Foundation.swift in Sources */, + 330C04EB6B7EBC2003CD24A79A08D54A /* HMAC.swift in Sources */, + 6FE1DFD7DAEA3A28CE8195074D607724 /* Int+Extension.swift in Sources */, + F9D1748CA6F11992315C2532934EE4BC /* MD5.swift in Sources */, + CE31A8F48BCBF803CD4E141E6BDED9A4 /* NoPadding.swift in Sources */, + 9A1DF7F0364E8E12E0C6D6CE25DBAD69 /* OFB.swift in Sources */, + 1334657041B050C16C12845B29EE07E7 /* Operators.swift in Sources */, + AC4A7F82DA71924C159A0F019EA6B14D /* Padding.swift in Sources */, + 01C9772E1A5DE079E7FBC2D7FE6152F3 /* PBKDF1.swift in Sources */, + D80597936DA978F70A2E6D7EC71282B3 /* PBKDF2.swift in Sources */, + 9EAAF055B1642982B8904E7D72620DB0 /* PCBC.swift in Sources */, + DD2E2CD6C02C74685463B15F71AA38E3 /* PKCS5.swift in Sources */, + F9B5B9564F737D9B8577DFC6E471FE68 /* PKCS7.swift in Sources */, + 12CEE670DF63F6C2AE4E2568A4628DBB /* PKCS7Padding.swift in Sources */, + 0A9B4D606A95D72A06EBD5DBE512442F /* Poly1305.swift in Sources */, + 86728D25113B805C9CB1679B7A5A1887 /* Rabbit+Foundation.swift in Sources */, + F78C24389C713F356E0494546F7751F2 /* Rabbit.swift in Sources */, + A9483F1921A4A994980A87F978BC7086 /* Scrypt.swift in Sources */, + 48D720BA973F7303DC3030D02345A89D /* SecureBytes.swift in Sources */, + 2280D5D148C48C58E4221FCA14ACDBC3 /* SHA1.swift in Sources */, + 6ECB086FCD9F99852D04EF7164799CAB /* SHA2.swift in Sources */, + 7F3CC364EE02234A5E36FAD7B3B413BF /* SHA3.swift in Sources */, + C9B7416EECE402B488F2FB80194D7E4A /* StreamDecryptor.swift in Sources */, + 506E22EADDEEED8CFF3E38C1F0E08BC8 /* StreamEncryptor.swift in Sources */, + 6251CAC2A279363E07554B3A8DA2CA80 /* String+Extension.swift in Sources */, + 39C27E5EB9E2DF685D7C901DD497DEDB /* String+FoundationExtension.swift in Sources */, + 52B20FDB0201028D86307F9946EBF8EF /* UInt128.swift in Sources */, + 0FA012BA03ADB4916413EBD05967348C /* UInt16+Extension.swift in Sources */, + 528E81E182861836E3CE7E4057649C4E /* UInt32+Extension.swift in Sources */, + CEA20537663F62BCEBEC9B6560A40796 /* UInt64+Extension.swift in Sources */, + D5D647DB518CED93C4D5F0C262255E6B /* UInt8+Extension.swift in Sources */, + 2E17D9A43A2E54513B66E7CFDC64FCF7 /* Updatable.swift in Sources */, + 35E1DEB2C8EF2909085BAD583DE3227F /* Utils+Foundation.swift in Sources */, + 97042F4038DDEB535F984C659D78D0BB /* Utils.swift in Sources */, + CAE2DF120825C5A145C6C9BB7503A495 /* ZeroPadding.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 859DA4A527C0326C3D5419DD708D65DD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5DC57AE11E0C4752497A7462AEEDF2CD /* Pods-Watch Extension-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 88E323CF228A17E09E87BE3A0B1626C2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7ACCDEDD9521549FA41E0E172447D2F5 /* AlamofireObjectMapper-watchOS-dummy.m in Sources */, + DD50DC39177440B69D76CE063CA3AC87 /* AlamofireObjectMapper.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8E7F8866EBFEE36995355437396282BE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DF9E902055B942E440A600199F26C71D /* CodableTransform.swift in Sources */, + 5C7DF7CB1BA993BA5CCB8E6CC73CFE61 /* CustomDateFormatTransform.swift in Sources */, + 34ABAAEAC7EE9C4385762FB7C166C4B6 /* DataTransform.swift in Sources */, + 259D02D2D2E5BC2695795D70FEA1CD6E /* DateFormatterTransform.swift in Sources */, + 5555FEBD264545E23926244CA9227C78 /* DateTransform.swift in Sources */, + 3AF4444EFD5EC930D252D8CE042A57BE /* DictionaryTransform.swift in Sources */, + 65479167C9E2EC75681DE5FE2F1D49FF /* EnumOperators.swift in Sources */, + 35AE5CBE8D974F9CF5D38BB642F897B0 /* EnumTransform.swift in Sources */, + D61632283DE47E05830AF9361BF9E178 /* FromJSON.swift in Sources */, + 3BB297A8AE0B782713C81CA176C92A3A /* HexColorTransform.swift in Sources */, + 59E350D6402F1CF88B07555C252A2352 /* ImmutableMappable.swift in Sources */, + 3FE9D5BA3BD766A36EBD01744DB78A99 /* IntegerOperators.swift in Sources */, + A477E26F53C09078BA003D36E997C151 /* ISO8601DateTransform.swift in Sources */, + 67F8FAACADDD58958FB8A0364C009600 /* Map.swift in Sources */, + A2F83CDFEA624C6C57C527F9F378D19A /* MapError.swift in Sources */, + A4F3413A8B6FD95BFB3C301CCB2FE7C3 /* Mappable.swift in Sources */, + F407208CBBF05D9333102FAF0480F31F /* Mapper.swift in Sources */, + 9360A96BD6459848ED6EF26D8DADFE5A /* NSDecimalNumberTransform.swift in Sources */, + 5AEE5105937ECF29037067F3EABCB37A /* ObjectMapper-iOS-dummy.m in Sources */, + A7439EE8D743922E845702130BE2541B /* Operators.swift in Sources */, + 3A2973BBB1EDAC4D6245B04D23900C3C /* ToJSON.swift in Sources */, + 7C62E119FC58DBE1655C2B09745837F5 /* TransformOf.swift in Sources */, + 73C444AF5780268AC3A7CBA1D9CB1245 /* TransformOperators.swift in Sources */, + 38BF185C5AAF151790AA556C9A302873 /* TransformType.swift in Sources */, + 6A6D0CECC921FB6D30A6C4686F47B346 /* URLTransform.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 974E16DE8E529288B187D5325D2CB7E1 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 9B809B1D23140B74109D2944D7B85370 /* AEAD.swift in Sources */, + 1909DF830712BD9329650FD08237EFDC /* AEADChaCha20Poly1305.swift in Sources */, + DBD47EC2D2068A32564D6BD2C2B20221 /* AES+Foundation.swift in Sources */, + E1803407BAA1F6EAA46DB10B3D9AE6BB /* AES.Cryptors.swift in Sources */, + 29134B8B1D648CFD82BFD8681DA80AFC /* AES.swift in Sources */, + 4AC172969396B67FC872C8569ADEE5EF /* Array+Extension.swift in Sources */, + 6932867F7689135CBD9ADF5FC3F5A6A0 /* Array+Foundation.swift in Sources */, + A69DBD7FB7755B51EA36FC6D8BA12704 /* Authenticator.swift in Sources */, + 67C5BAF5A9E17BFDE623472406575D6A /* BatchedCollection.swift in Sources */, + 101FDC1EA6AA25642A56000BD82A334F /* Bit.swift in Sources */, + B64A4FB37BAF466D996B76B8636F9924 /* BlockCipher.swift in Sources */, + F793BF43B1DC4C85E6DF77DB25165BC8 /* BlockDecryptor.swift in Sources */, + 530D331BD4A81AE8DAE49D35B345D9FB /* BlockEncryptor.swift in Sources */, + 6CB0DE96D5AD0C23CF4ABC303BB01513 /* BlockMode.swift in Sources */, + 80DA6F9F783B2D77812FD51927CCB0A1 /* BlockModeOptions.swift in Sources */, + E4887126524555D98F7C26807C8C872D /* Blowfish+Foundation.swift in Sources */, + C55991A2CFE9D69CCFAFAAB47481A583 /* Blowfish.swift in Sources */, + 15AC30A00CE77675A4056CA8275DD59D /* CBC.swift in Sources */, + 228FBB88050A6A43ED63E5A246FA5B79 /* CBCMAC.swift in Sources */, + C4DFB892A3B6CAB1BDFCF0C2D2BA3DE5 /* CCM.swift in Sources */, + C6466A8C86E3207B73F20437B8E13999 /* CFB.swift in Sources */, + E58AFF30DC5FB85967E17B104B7C436F /* ChaCha20+Foundation.swift in Sources */, + 59B09F25C480FA889EE6C6F69C8BE2CA /* ChaCha20.swift in Sources */, + 94B030B37731DFF25193BE88E5A3C40D /* Checksum.swift in Sources */, + D12F579CEE2B66C02EC6B6A5FDE38A81 /* Cipher.swift in Sources */, + 193A61B46B136D8CE523CFB4994E623B /* CipherModeWorker.swift in Sources */, + 903A7D735806F25CA810601309FF000E /* CMAC.swift in Sources */, + 1765073CE326EF43C6EE2DA39EEF0CD9 /* Collection+Extension.swift in Sources */, + 0EAB0E9ACA5D88F58AA2A2C02D593EB4 /* CompactMap.swift in Sources */, + 550D8614A47C99CCE668BFD0AB127879 /* Cryptor.swift in Sources */, + 3C001B71C94B9E90FDFBF9D594A42ACA /* Cryptors.swift in Sources */, + 1053A51877CBF516A6DE82C3C4933FB0 /* CryptoSwift-iOS-dummy.m in Sources */, + AB65FF8297EA4D6868602C0113CCA839 /* CTR.swift in Sources */, + 91052846D92E85DDAAD5CD2813507211 /* Data+Extension.swift in Sources */, + B60DDBD5F90AB17045F9A9CC4B24EEFB /* Digest.swift in Sources */, + F20DC2AD815B177396D8BB45C3888751 /* DigestType.swift in Sources */, + B3B70E729B9DBE6F4738BC9CFBDECD04 /* ECB.swift in Sources */, + 6823E48E063CE19E4C605DE25E26E70E /* GCM.swift in Sources */, + F4A127D0320C2D561CE43ADC6BEAFB73 /* Generics.swift in Sources */, + 864D17E2FE8121867019C30E59BE5E21 /* HKDF.swift in Sources */, + AF205ABAAF2755544370C160DC8EC490 /* HMAC+Foundation.swift in Sources */, + DEC1CD260AED653C6C70863D47680E0B /* HMAC.swift in Sources */, + 92C3F61E498DE72314339CC891054DC4 /* Int+Extension.swift in Sources */, + 2ECBC16CCB9AF65A0E7E9CAE58EB0EBF /* MD5.swift in Sources */, + 340D5C77FD74AEC59AF2A8C4F1B102D4 /* NoPadding.swift in Sources */, + 382047EE1CDB7D26194BCCCC8F779A50 /* OFB.swift in Sources */, + DBE9B8656C8F9F173B4FDDDB63CBF2EF /* Operators.swift in Sources */, + 85248F7BF0AE3162DE7C37FBEACAA6D9 /* Padding.swift in Sources */, + 51835F4DBA7535D3B273EC544DA0BD60 /* PBKDF1.swift in Sources */, + 209330C37BEC7FAC01804014E708EE5A /* PBKDF2.swift in Sources */, + 9F587E6B4E3402F772D1520A97CB85F8 /* PCBC.swift in Sources */, + 1350592B2C2AD5C48612BF939DF2A947 /* PKCS5.swift in Sources */, + 3A658CB4FD7BA8211392A42DF64748A3 /* PKCS7.swift in Sources */, + FD64536EC4128B709C73E634866C7987 /* PKCS7Padding.swift in Sources */, + 121F2D109820CA5800F300E7CF97FBC7 /* Poly1305.swift in Sources */, + 940B03BF74329B97EAD34FE317F7F1F7 /* Rabbit+Foundation.swift in Sources */, + 554388F18CCBC9BEF055514CF53E9413 /* Rabbit.swift in Sources */, + F794078DB0BFC4ECA72352AAF90EFE4A /* Scrypt.swift in Sources */, + 0D69C28600D92940039DAAB37F45E48B /* SecureBytes.swift in Sources */, + E079A0DB030F050D9E1EC03B9B2585AC /* SHA1.swift in Sources */, + 26A738B4C8DD72611403735CFA0F4F4A /* SHA2.swift in Sources */, + 75BD6C90A7F4588FEA91C1C702D9A0C0 /* SHA3.swift in Sources */, + 1CC6530ED1A250FB08C5882CE508A02B /* StreamDecryptor.swift in Sources */, + 7FD7936CD655B149A2F525161A9F6E6D /* StreamEncryptor.swift in Sources */, + 16A529D53801C06C358DCF0CCB76BEA9 /* String+Extension.swift in Sources */, + 7D2E607FB3630D77F3F0DB8CC3C99195 /* String+FoundationExtension.swift in Sources */, + 20DF8618EB52318E1E409E7950251B8A /* UInt128.swift in Sources */, + C8C4339B907EE129905A88770D62E25F /* UInt16+Extension.swift in Sources */, + 3D1ABD34F6BAFA66CAAD4E0BAB945E27 /* UInt32+Extension.swift in Sources */, + 81A2A8BB1E7BE4BE8EAA7AE4E2C7573F /* UInt64+Extension.swift in Sources */, + 2FE23977B15D0922051184A46056425B /* UInt8+Extension.swift in Sources */, + D486967D802581AD706F178CFAB88147 /* Updatable.swift in Sources */, + CDBEF9271A3D4CAD33C10DFFEAE24431 /* Utils+Foundation.swift in Sources */, + AF3BAC08E78954BD1E344D7E6A0C066F /* Utils.swift in Sources */, + 51BD479F01C6053255A3DEC67D681CCC /* ZeroPadding.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B18779B2D274BA5E6E71E6E021C699DF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5CE203E4D16F633214A031EF544278F0 /* Pods-BSRadioWaves-dummy.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B789942D8246A09D6E58D91FDC0BDD72 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 838BAC4654B08C65FCC286FC2E0061DA /* CodableTransform.swift in Sources */, + 31288D2789EA9FCE04805CDFC16168CB /* CustomDateFormatTransform.swift in Sources */, + 9EE2A1ADB2CE1B2682639A9CC596F997 /* DataTransform.swift in Sources */, + 546CF5C1DD38A2FDFBC185F1C3A2BF3E /* DateFormatterTransform.swift in Sources */, + EC6F596A19B56DB0470BFEDC6445F224 /* DateTransform.swift in Sources */, + 387B9B2271DBD4A689CE452A83552AFA /* DictionaryTransform.swift in Sources */, + F65EF8AB866F591B590E768F116A4A6E /* EnumOperators.swift in Sources */, + BCE8F32EB03AFB8A28A6D42267C527BD /* EnumTransform.swift in Sources */, + 13452BD15063340D3611D43BEB1F5180 /* FromJSON.swift in Sources */, + 2EC66BF077ECDCADC7A590740DF631DC /* HexColorTransform.swift in Sources */, + C671C085675E3F739DA0FFCB1C56E667 /* ImmutableMappable.swift in Sources */, + A1200D1514F89E19300D9F272856845E /* IntegerOperators.swift in Sources */, + EFBEBAF457182E041C47739505468482 /* ISO8601DateTransform.swift in Sources */, + 532CFEA5CEDB2C143A4903C1DBEF99DB /* Map.swift in Sources */, + 45E6DA0D9A897FC4AF1A2BD354D7596D /* MapError.swift in Sources */, + 9ABA6D814581D90649BB715E37C31758 /* Mappable.swift in Sources */, + 23FC3D80C6D35D07CD1ADD7153A6AC97 /* Mapper.swift in Sources */, + BCA271D3F60C2BB48588E45A038ABABB /* NSDecimalNumberTransform.swift in Sources */, + A08F1D18CABBDCBE14D5BE2A7D352D24 /* ObjectMapper-watchOS-dummy.m in Sources */, + 4AD74B38ED3F019D40994B16DD6BCA06 /* Operators.swift in Sources */, + B8B5DBE63811D7D77F500DB12838FFD8 /* ToJSON.swift in Sources */, + C5672C4E73195617642F968F5775A50A /* TransformOf.swift in Sources */, + 1F815330CE9D869EE23CDAB57FE96921 /* TransformOperators.swift in Sources */, + 5B038F87B1FD86C4ADD0A2B0DA18643C /* TransformType.swift in Sources */, + 7ECE948FC4ECA85A3F8E865244225390 /* URLTransform.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 1507F591A681CFA06E38090281E33383 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "SDWebImage-watchOS"; + target = 6447A5D6B2905FE6A09B0ABC0042EC50 /* SDWebImage-watchOS */; + targetProxy = 4FA4D2B70C3DED3901BB28F4E4653533 /* PBXContainerItemProxy */; + }; + 255502416A4E946183035BBAF81BB38B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "CryptoSwift-iOS"; + target = 218BFCBCA0EA83AEA95CE87303914A04 /* CryptoSwift-iOS */; + targetProxy = F353203ADC2154712A4E986A2F529989 /* PBXContainerItemProxy */; + }; + 32557E8D9DF53089C05A72A2DC94659F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Alamofire-iOS"; + target = FD8828BFC368157226E204A32CD5B6DE /* Alamofire-iOS */; + targetProxy = 1447A4A082CA04D2ACA478851CC4AADE /* PBXContainerItemProxy */; + }; + 34F0B85E8BA3D68B14296C04D5D492A6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "CryptoSwift-watchOS"; + target = 2FD806DB695223C0672239A9FE30B913 /* CryptoSwift-watchOS */; + targetProxy = B230A7274FDE0922425A9C41E261F5A0 /* PBXContainerItemProxy */; + }; + 3CCEA9B51C6A5BEB7EB7732442C69DEA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Alamofire-watchOS"; + target = 66F51BC925FD5FB829E8D422C690BDF0 /* Alamofire-watchOS */; + targetProxy = 63C69FAE89ADC8A2AEB89D90F547EF56 /* PBXContainerItemProxy */; + }; + 41B08F091A3DC9DB9D83A6D8E371577F /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "SDWebImage-iOS"; + target = 744F52F389060600FE79F1B9A709C630 /* SDWebImage-iOS */; + targetProxy = 3C8E35F0422AB550C6F1D3FE2FF8AC3E /* PBXContainerItemProxy */; + }; + 505E5A61DFD0EAAA199C9E9563624FB2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "ObjectMapper-watchOS"; + target = 77F4321EB2A71321DE0D59BDF4C62E3F /* ObjectMapper-watchOS */; + targetProxy = C26F605802FB1E6E3F0A5F827E2A9577 /* PBXContainerItemProxy */; + }; + 7416035C3BE41EE17E3D2CF8A3F0F66A /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "ObjectMapper-iOS"; + target = D01A02B225FD29F76E911D60DBFD443C /* ObjectMapper-iOS */; + targetProxy = 124EE9D94BF992283F49103CBB9EC1C5 /* PBXContainerItemProxy */; + }; + 77FC4B82915BFDB6ECEF301D2D21E02B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "ObjectMapper-iOS"; + target = D01A02B225FD29F76E911D60DBFD443C /* ObjectMapper-iOS */; + targetProxy = 23682F5127A4EF0AEAC9B59E3DF7CE2E /* PBXContainerItemProxy */; + }; + 899926C8C99AB48DFF1F940D4FF16612 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "AlamofireObjectMapper-watchOS"; + target = 739D23BF96457378860369EA2DA315C9 /* AlamofireObjectMapper-watchOS */; + targetProxy = E5D5321B1256D957685B195DBB384219 /* PBXContainerItemProxy */; + }; + 9A3E4F97EBA370D28EF1E42929233CC1 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Alamofire-watchOS"; + target = 66F51BC925FD5FB829E8D422C690BDF0 /* Alamofire-watchOS */; + targetProxy = 8AF4C5A939DC7945A7CFABDEEB8852E4 /* PBXContainerItemProxy */; + }; + AD80CD311D364F8A33C0BF5402CA6D12 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Toast-Swift"; + target = B990BD87169C76A3ED3FE8A9258D91A3 /* Toast-Swift */; + targetProxy = BF57240D2D33AE990266C4D0E1832B7A /* PBXContainerItemProxy */; + }; + C05BB58C6B789082AE34C92160E64E23 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "ObjectMapper-watchOS"; + target = 77F4321EB2A71321DE0D59BDF4C62E3F /* ObjectMapper-watchOS */; + targetProxy = A75EF66A4345AFDA41E7F6D19DD81BF1 /* PBXContainerItemProxy */; + }; + ED8C926256AC2BB881CEDD40E826AA01 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "Alamofire-iOS"; + target = FD8828BFC368157226E204A32CD5B6DE /* Alamofire-iOS */; + targetProxy = 8533914E134A5C153EA97FF41FA205AE /* PBXContainerItemProxy */; + }; + FB919FA21E1BAC9083AC1E0A7F4E05FD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "AlamofireObjectMapper-iOS"; + target = 7B450F2E8D53215597AEE594BA0BB14B /* AlamofireObjectMapper-iOS */; + targetProxy = 6597C94C9047056BD950B5D106680791 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 0C1C94865FCD65D66D9B1F6D0935558C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_DEBUG=1", + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + WATCHOS_DEPLOYMENT_TARGET = 4.0; + }; + name = Debug; + }; + 0CCCAAB6307865E86431A071FC25893C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 56E95B11A8DE03F6CA005AD960DC0E2B /* ObjectMapper-iOS.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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/ObjectMapper-iOS/ObjectMapper-iOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS.modulemap"; + PRODUCT_MODULE_NAME = ObjectMapper; + PRODUCT_NAME = ObjectMapper; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 0D8EDD7DBF365261DF5C731FFC65937E /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EEB78B7A16086FD0A25EACF4BD9D3BBA /* ObjectMapper-watchOS.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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/ObjectMapper-watchOS/ObjectMapper-watchOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS.modulemap"; + PRODUCT_MODULE_NAME = ObjectMapper; + PRODUCT_NAME = ObjectMapper; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + 0E5728FAF272040BDE3DCDA78BA61731 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 56E95B11A8DE03F6CA005AD960DC0E2B /* ObjectMapper-iOS.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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/ObjectMapper-iOS/ObjectMapper-iOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS.modulemap"; + PRODUCT_MODULE_NAME = ObjectMapper; + PRODUCT_NAME = ObjectMapper; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 1248746167A125C40DDE19811F48DFB2 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4BB746D5F5ED9B9B024F39461D914A43 /* Alamofire-watchOS.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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-watchOS/Alamofire-watchOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Alamofire-watchOS/Alamofire-watchOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Alamofire-watchOS/Alamofire-watchOS.modulemap"; + PRODUCT_MODULE_NAME = Alamofire; + PRODUCT_NAME = Alamofire; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.1; + TARGETED_DEVICE_FAMILY = 4; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + 1FF09DC0FE3E686EEE2DB1B7E24EB849 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2B3248A4BA39C7307B86266A2A7881B5 /* SDWebImage-watchOS.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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/SDWebImage-watchOS/SDWebImage-watchOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS.modulemap"; + PRODUCT_MODULE_NAME = SDWebImage; + PRODUCT_NAME = SDWebImage; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + 255F8901D2211CC49112429D3E59148A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = EEB78B7A16086FD0A25EACF4BD9D3BBA /* ObjectMapper-watchOS.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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/ObjectMapper-watchOS/ObjectMapper-watchOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS.modulemap"; + PRODUCT_MODULE_NAME = ObjectMapper; + PRODUCT_NAME = ObjectMapper; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + 288D750DCEAE0878100F7590C4990063 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "POD_CONFIGURATION_RELEASE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + STRIP_INSTALLED_PRODUCT = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; + SYMROOT = "${SRCROOT}/../build"; + WATCHOS_DEPLOYMENT_TARGET = 4.0; + }; + name = Release; + }; + 2D53FBD333C13B6E90E4D9398B9E96C6 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3CA27772B0C1545A46B4A7DD89A4C8C8 /* Alamofire-iOS.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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-iOS/Alamofire-iOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Alamofire-iOS/Alamofire-iOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Alamofire-iOS/Alamofire-iOS.modulemap"; + PRODUCT_MODULE_NAME = Alamofire; + PRODUCT_NAME = Alamofire; + 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; + }; + 545F4B3DF0D11A496F4BEDCB0AF67BC6 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 17CAAB77FCDE6347454F7A923FD58ACE /* SDWebImage-iOS.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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/SDWebImage-iOS/SDWebImage-iOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SDWebImage-iOS/SDWebImage-iOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/SDWebImage-iOS/SDWebImage-iOS.modulemap"; + PRODUCT_MODULE_NAME = SDWebImage; + PRODUCT_NAME = SDWebImage; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 5ECE239D7BBE475DCF11F592604A1B52 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ABD1CE72B66B1C49F0FF065F377D5D1D /* CryptoSwift-iOS.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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/CryptoSwift-iOS/CryptoSwift-iOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS.modulemap"; + PRODUCT_MODULE_NAME = CryptoSwift; + PRODUCT_NAME = CryptoSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 6F06125B9444CF71057F922D3E44E9FF /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 91D130F38253D5A09A952C63F39991D6 /* Pods-Watch Extension.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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"; + INFOPLIST_FILE = "Target Support Files/Pods-Watch Extension/Pods-Watch Extension-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Watch Extension/Pods-Watch Extension.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 4.0; + }; + name = Debug; + }; + 744FA2B0BB0F34E179829937D55723A2 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 1F4753D1AB10D773CEF9839DE1B95FF4 /* Pods-Watch Extension.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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"; + INFOPLIST_FILE = "Target Support Files/Pods-Watch Extension/Pods-Watch Extension-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-Watch Extension/Pods-Watch Extension.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = 4; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 4.0; + }; + name = Release; + }; + 7CE6E058FF47BC910EA2A3854E9D4682 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FB7EAA2156AED0A96332A66A1C079425 /* Pods-BSRadioWaves.release.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGN_IDENTITY = ""; + "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"; + INFOPLIST_FILE = "Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 8D469425B4E86D1FEFB38740A09933EF /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D5B9891757DED528F5331BE36C99DB21 /* AlamofireObjectMapper-watchOS.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.modulemap"; + PRODUCT_MODULE_NAME = AlamofireObjectMapper; + PRODUCT_NAME = AlamofireObjectMapper; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + 9187999B6A355603837D5868DCFAC225 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ABD1CE72B66B1C49F0FF065F377D5D1D /* CryptoSwift-iOS.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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/CryptoSwift-iOS/CryptoSwift-iOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS.modulemap"; + PRODUCT_MODULE_NAME = CryptoSwift; + PRODUCT_NAME = CryptoSwift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 98898C6F52A6A7DBE554A243A24C2F51 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ADD5E5583AA88157F0956EFFC762F822 /* Toast-Swift.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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/Toast-Swift/Toast-Swift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Toast-Swift/Toast-Swift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Toast-Swift/Toast-Swift.modulemap"; + PRODUCT_MODULE_NAME = Toast_Swift; + PRODUCT_NAME = Toast_Swift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 9D182A25167F323DAFBD9FAAA7A41B5D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DC267E6F43516A7C27F06B035D869846 /* CryptoSwift-watchOS.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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/CryptoSwift-watchOS/CryptoSwift-watchOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS.modulemap"; + PRODUCT_MODULE_NAME = CryptoSwift; + PRODUCT_NAME = CryptoSwift; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + 9DA1F9915E2EB27EC7ED4954F20EA104 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 30CAAA388CF42B22A57E09222AB587F3 /* Pods-BSRadioWaves.debug.xcconfig */; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; + CLANG_ENABLE_OBJC_WEAK = NO; + CODE_SIGN_IDENTITY = ""; + "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"; + INFOPLIST_FILE = "Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MACH_O_TYPE = staticlib; + MODULEMAP_FILE = "Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.modulemap"; + OTHER_LDFLAGS = ""; + OTHER_LIBTOOLFLAGS = ""; + PODS_ROOT = "$(SRCROOT)"; + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 9F179C2EEA65F56DBCA8965433039D53 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D5B9891757DED528F5331BE36C99DB21 /* AlamofireObjectMapper-watchOS.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.modulemap"; + PRODUCT_MODULE_NAME = AlamofireObjectMapper; + PRODUCT_NAME = AlamofireObjectMapper; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = 4; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + A402670AAF1C949A44BF568959C663BB /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 17CAAB77FCDE6347454F7A923FD58ACE /* SDWebImage-iOS.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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/SDWebImage-iOS/SDWebImage-iOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SDWebImage-iOS/SDWebImage-iOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/SDWebImage-iOS/SDWebImage-iOS.modulemap"; + PRODUCT_MODULE_NAME = SDWebImage; + PRODUCT_NAME = SDWebImage; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + A484F399C5A6B34A2F5B20CC4452572F /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2B3248A4BA39C7307B86266A2A7881B5 /* SDWebImage-watchOS.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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/SDWebImage-watchOS/SDWebImage-watchOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS.modulemap"; + PRODUCT_MODULE_NAME = SDWebImage; + PRODUCT_NAME = SDWebImage; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 4.0; + TARGETED_DEVICE_FAMILY = 4; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Release; + }; + B4AF3386EE7EEF473F41FCF618DFFCF7 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DC267E6F43516A7C27F06B035D869846 /* CryptoSwift-watchOS.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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/CryptoSwift-watchOS/CryptoSwift-watchOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS.modulemap"; + PRODUCT_MODULE_NAME = CryptoSwift; + PRODUCT_NAME = CryptoSwift; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + C39BAD945D45E666A8ACC46B0B537678 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7CC0AABB51E0E51C0E0A59F4615CC6D3 /* AlamofireObjectMapper-iOS.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS.modulemap"; + PRODUCT_MODULE_NAME = AlamofireObjectMapper; + PRODUCT_NAME = AlamofireObjectMapper; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + C4A975AEF15FAFBB671EA74CDD00C8B9 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 3CA27772B0C1545A46B4A7DD89A4C8C8 /* Alamofire-iOS.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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-iOS/Alamofire-iOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Alamofire-iOS/Alamofire-iOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Alamofire-iOS/Alamofire-iOS.modulemap"; + PRODUCT_MODULE_NAME = Alamofire; + PRODUCT_NAME = Alamofire; + 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; + }; + CD7870636F745E30F1B099E99188096F /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 4BB746D5F5ED9B9B024F39461D914A43 /* Alamofire-watchOS.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + "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-watchOS/Alamofire-watchOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Alamofire-watchOS/Alamofire-watchOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Alamofire-watchOS/Alamofire-watchOS.modulemap"; + PRODUCT_MODULE_NAME = Alamofire; + PRODUCT_NAME = Alamofire; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.1; + TARGETED_DEVICE_FAMILY = 4; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + WATCHOS_DEPLOYMENT_TARGET = 2.0; + }; + name = Debug; + }; + F3D7AA7B6797C4885E6D6232E7580830 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ADD5E5583AA88157F0956EFFC762F822 /* Toast-Swift.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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/Toast-Swift/Toast-Swift-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/Toast-Swift/Toast-Swift-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/Toast-Swift/Toast-Swift.modulemap"; + PRODUCT_MODULE_NAME = Toast_Swift; + PRODUCT_NAME = Toast_Swift; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + FFB7FE2C8727624D46274A0AC4C2EBC8 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7CC0AABB51E0E51C0E0A59F4615CC6D3 /* AlamofireObjectMapper-iOS.xcconfig */; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + "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/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-prefix.pch"; + INFOPLIST_FILE = "Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + MODULEMAP_FILE = "Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS.modulemap"; + PRODUCT_MODULE_NAME = AlamofireObjectMapper; + PRODUCT_NAME = AlamofireObjectMapper; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 28EC073B2BB88BD95A70D724104E5021 /* Build configuration list for PBXNativeTarget "Pods-Watch Extension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6F06125B9444CF71057F922D3E44E9FF /* Debug */, + 744FA2B0BB0F34E179829937D55723A2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0C1C94865FCD65D66D9B1F6D0935558C /* Debug */, + 288D750DCEAE0878100F7590C4990063 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 53A55F5440CDA2072D66FB8102A72827 /* Build configuration list for PBXNativeTarget "AlamofireObjectMapper-watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8D469425B4E86D1FEFB38740A09933EF /* Debug */, + 9F179C2EEA65F56DBCA8965433039D53 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7F7B1A606984012F6CCE51C309204FBC /* Build configuration list for PBXNativeTarget "CryptoSwift-watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B4AF3386EE7EEF473F41FCF618DFFCF7 /* Debug */, + 9D182A25167F323DAFBD9FAAA7A41B5D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8005A8EEDAB9F7878D1828CE167C4F68 /* Build configuration list for PBXNativeTarget "CryptoSwift-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9187999B6A355603837D5868DCFAC225 /* Debug */, + 5ECE239D7BBE475DCF11F592604A1B52 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8D0F46248CC8E71F9C2CDB6D55831EA4 /* Build configuration list for PBXNativeTarget "Pods-BSRadioWaves" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9DA1F9915E2EB27EC7ED4954F20EA104 /* Debug */, + 7CE6E058FF47BC910EA2A3854E9D4682 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + AB249E6B9302267A487C5B3C2CDEE10E /* Build configuration list for PBXNativeTarget "ObjectMapper-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0CCCAAB6307865E86431A071FC25893C /* Debug */, + 0E5728FAF272040BDE3DCDA78BA61731 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B8C401847A53B4C2810311A8CBD715AD /* Build configuration list for PBXNativeTarget "Toast-Swift" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 98898C6F52A6A7DBE554A243A24C2F51 /* Debug */, + F3D7AA7B6797C4885E6D6232E7580830 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BA5FCF9126572083B3E946EC76DD8512 /* Build configuration list for PBXNativeTarget "AlamofireObjectMapper-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FFB7FE2C8727624D46274A0AC4C2EBC8 /* Debug */, + C39BAD945D45E666A8ACC46B0B537678 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C8E8FF18B09E22C119FDC1766EDCA98E /* Build configuration list for PBXNativeTarget "SDWebImage-watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1FF09DC0FE3E686EEE2DB1B7E24EB849 /* Debug */, + A484F399C5A6B34A2F5B20CC4452572F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D45F63E4A3CBD4DDABC72806CC0FAD29 /* Build configuration list for PBXNativeTarget "ObjectMapper-watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 255F8901D2211CC49112429D3E59148A /* Debug */, + 0D8EDD7DBF365261DF5C731FFC65937E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E61069F691B31002ED13C26F610A6144 /* Build configuration list for PBXNativeTarget "Alamofire-watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CD7870636F745E30F1B099E99188096F /* Debug */, + 1248746167A125C40DDE19811F48DFB2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + E65E740C96442990E6E9CDF05EE3EFEF /* Build configuration list for PBXNativeTarget "Alamofire-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C4A975AEF15FAFBB671EA74CDD00C8B9 /* Debug */, + 2D53FBD333C13B6E90E4D9398B9E96C6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FA578CEFC64D098EA954DA0C3584D935 /* Build configuration list for PBXNativeTarget "SDWebImage-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 545F4B3DF0D11A496F4BEDCB0AF67BC6 /* Debug */, + A402670AAF1C949A44BF568959C663BB /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */; +} diff --git a/Pods/SDWebImage/LICENSE b/Pods/SDWebImage/LICENSE new file mode 100644 index 0000000..92a252a --- /dev/null +++ b/Pods/SDWebImage/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/Pods/SDWebImage/README.md b/Pods/SDWebImage/README.md new file mode 100644 index 0000000..3328f5d --- /dev/null +++ b/Pods/SDWebImage/README.md @@ -0,0 +1,203 @@ +

+ +

+ + +[![Build Status](http://img.shields.io/travis/SDWebImage/SDWebImage/master.svg?style=flat)](https://travis-ci.org/SDWebImage/SDWebImage) +[![Pod Version](http://img.shields.io/cocoapods/v/SDWebImage.svg?style=flat)](http://cocoadocs.org/docsets/SDWebImage/) +[![Pod Platform](http://img.shields.io/cocoapods/p/SDWebImage.svg?style=flat)](http://cocoadocs.org/docsets/SDWebImage/) +[![Pod License](http://img.shields.io/cocoapods/l/SDWebImage.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0.html) +[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/SDWebImage/SDWebImage) +[![codecov](https://codecov.io/gh/SDWebImage/SDWebImage/branch/master/graph/badge.svg)](https://codecov.io/gh/SDWebImage/SDWebImage) + +This library provides an async image downloader with cache support. For convenience, we added categories for UI elements like `UIImageView`, `UIButton`, `MKAnnotationView`. + +## Features + +- [x] Categories for `UIImageView`, `UIButton`, `MKAnnotationView` adding web image and cache management +- [x] An asynchronous image downloader +- [x] An asynchronous memory + disk image caching with automatic cache expiration handling +- [x] A background image decompression +- [x] A guarantee that the same URL won't be downloaded several times +- [x] A guarantee that bogus URLs won't be retried again and again +- [x] A guarantee that main thread will never be blocked +- [x] Performances! +- [x] Use GCD and ARC + +## Supported Image Formats + +- Image formats supported by UIImage (JPEG, PNG, ...), including GIF +- WebP format, including animated WebP (use the `WebP` subspec) +- Support extendable coder plugins for new image formats. Like APNG, BPG, HFIF, SVG, etc. See all the list in [Image coder plugin List](https://github.com/SDWebImage/SDWebImage/wiki/Coder-Plugin-List) + +## Beta version + +SDWebImage's 5.0 version is nearing completion. Which introduce many new features like Animated ImageView and Transformer. We also provide a more modularized design used for advanced user customization. + +You can check the latest [5.x branch](https://github.com/SDWebImage/SDWebImage/tree/5.x) to know about the current status. We'd love you to have a try with the beta version and provide any feedback. If you'd love, check [SDWebImage 5.0 Migration Guide](https://github.com/SDWebImage/SDWebImage/wiki/5.0-Migration-guide) and prepare for the migration. + +## Requirements + +- iOS 7.0 or later +- tvOS 9.0 or later +- watchOS 2.0 or later +- macOS 10.9 or later +- Xcode 7.3 or later + +#### Backwards compatibility + +- For iOS 5 and 6, use [any 3.x version up to 3.7.6](https://github.com/SDWebImage/SDWebImage/tree/3.7.6) +- For iOS < 5.0, please use the last [2.0 version](https://github.com/SDWebImage/SDWebImage/tree/2.0-compat). + +## Getting Started + +- Read this Readme doc +- Read the [How to use section](https://github.com/SDWebImage/SDWebImage#how-to-use) +- Read the [Documentation @ CocoaDocs](http://cocoadocs.org/docsets/SDWebImage/) +- Try the example by downloading the project from Github or even easier using CocoaPods try `pod try SDWebImage` +- Read the [Installation Guide](https://github.com/SDWebImage/SDWebImage/wiki/Installation-Guide) +- Read the [SDWebImage 4.0 Migration Guide](Docs/SDWebImage-4.0-Migration-guide.md) to get an idea of the changes from 3.x to 4.x +- Read the [Common Problems](https://github.com/SDWebImage/SDWebImage/wiki/Common-Problems) to find the solution for common problems +- Go to the [Wiki Page](https://github.com/SDWebImage/SDWebImage/wiki) for more information such as [Advanced Usage](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage) + +## Who Uses It +- Find out [who uses SDWebImage](https://github.com/SDWebImage/SDWebImage/wiki/Who-Uses-SDWebImage) and add your app to the list. + +## Communication + +- If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/sdwebimage). (Tag 'sdwebimage') +- If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/sdwebimage). +- If you **found a bug**, open an issue. +- If you **have a feature request**, open an issue. +- If you **want to contribute**, submit a pull request. + +## How To Use + +* Objective-C + +```objective-c +#import +... +[imageView sd_setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] + placeholderImage:[UIImage imageNamed:@"placeholder.png"]]; +``` + +* Swift + +```swift +import SDWebImage + +imageView.sd_setImage(with: URL(string: "http://www.domain.com/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png")) +``` + +- For details about how to use the library and clear examples, see [The detailed How to use](Docs/HowToUse.md) + +## Animated Images (GIF) support + +- Starting with the 4.0 version, we rely on [FLAnimatedImage](https://github.com/Flipboard/FLAnimatedImage) to take care of our animated images. +- If you use cocoapods, add `pod 'SDWebImage/GIF'` to your podfile. +- To use it, simply make sure you use `FLAnimatedImageView` instead of `UIImageView`. +- **Note**: there is a backwards compatible feature, so if you are still trying to load a GIF into a `UIImageView`, it will only show the 1st frame as a static image by default. However, you can enable the full GIF support by using the built-in GIF coder. See [GIF coder](https://github.com/SDWebImage/SDWebImage/wiki/Advanced-Usage#gif-coder) +- **Important**: FLAnimatedImage only works on the iOS platform. For macOS, use `NSImageView` with `animates` set to `YES` to show the entire animated images and `NO` to only show the 1st frame. For all the other platforms (tvOS, watchOS) we will fallback to the backwards compatibility feature described above + +## Installation + +There are three ways to use SDWebImage in your project: +- using CocoaPods +- using Carthage +- by cloning the project into your repository + +### Installation with CocoaPods + +[CocoaPods](http://cocoapods.org/) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries in your projects. See the [Get Started](http://cocoapods.org/#get_started) section for more details. + +#### Podfile +``` +platform :ios, '7.0' +pod 'SDWebImage', '~> 4.0' +``` + +##### Swift and static framework + +Swift project previously have to use `use_frameworks!` to make all Pods into dynamic framework to let CocoaPods works. + +However, start with `CocoaPods 1.5.0+` (with `Xcode 9+`), which supports to build both Objective-C && Swift code into static framework. You can use modular headers to use SDWebImage as static framework, without the need of `use_frameworks!`: + +``` +platform :ios, '8.0' +# Uncomment the next line when you want all Pods as static framework +# use_modular_headers! +pod 'SDWebImage', :modular_headers => true +``` + +See more on [CocoaPods 1.5.0 — Swift Static Libraries](http://blog.cocoapods.org/CocoaPods-1.5.0/) + +If not, you still need to add `use_frameworks!` to use SDWebImage as dynamic framework: + +``` +platform :ios, '8.0' +use_frameworks! +pod 'SDWebImage' +``` + +#### Subspecs + +There are 4 subspecs available now: `Core`, `MapKit`, `GIF` and `WebP` (this means you can install only some of the SDWebImage modules. By default, you get just `Core`, so if you need `WebP`, you need to specify it). + +Podfile example: +``` +pod 'SDWebImage/WebP' +``` + +### Installation with Carthage (iOS 8+) + +[Carthage](https://github.com/Carthage/Carthage) is a lightweight dependency manager for Swift and Objective-C. It leverages CocoaTouch modules and is less invasive than CocoaPods. + +To install with carthage, follow the instruction on [Carthage](https://github.com/Carthage/Carthage) + +#### Cartfile +``` +github "SDWebImage/SDWebImage" +``` + +### Installation by cloning the repository +- see [Manual install](Docs/ManualInstallation.md) + +### Import headers in your source files + +In the source files where you need to use the library, import the header file: + +```objective-c +#import +``` + +### Build Project + +At this point your workspace should build without error. If you are having problem, post to the Issue and the +community can help you solve it. + +## Author +- [Olivier Poitrey](https://github.com/rs) + +## Collaborators +- [Konstantinos K.](https://github.com/mythodeia) +- [Bogdan Poplauschi](https://github.com/bpoplauschi) +- [Chester Liu](https://github.com/skyline75489) +- [DreamPiggy](https://github.com/dreampiggy) +- [Wu Zhong](https://github.com/zhongwuzw) + +## Licenses + +All source code is licensed under the [MIT License](https://raw.github.com/SDWebImage/SDWebImage/master/LICENSE). + +## Architecture + +

+ +

+ +

+ +

+ + diff --git a/Pods/SDWebImage/SDWebImage/NSButton+WebCache.h b/Pods/SDWebImage/SDWebImage/NSButton+WebCache.h new file mode 100644 index 0000000..57f7115 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/NSButton+WebCache.h @@ -0,0 +1,259 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +#if SD_MAC + +#import "SDWebImageManager.h" + +@interface NSButton (WebCache) + +#pragma mark - Image + +/** + * Get the current image URL. + */ +- (nullable NSURL *)sd_currentImageURL; + +/** + * Set the button `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT; + +/** + * Set the button `image` with an `url` and a placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @see sd_setImageWithURL:placeholderImage:options: + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; + +/** + * Set the button `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; + +/** + * Set the button `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the button `image` with an `url`, placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; + +/** + * Set the button `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the button `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + +#pragma mark - Alternate Image + +/** + * Get the current alternateImage URL. + */ +- (nullable NSURL *)sd_currentAlternateImageURL; + +/** + * Set the button `alternateImage` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the alternateImage. + */ +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT; + +/** + * Set the button `alternateImage` with an `url` and a placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the alternateImage. + * @param placeholder The alternateImage to be set initially, until the alternateImage request finishes. + * @see sd_setAlternateImageWithURL:placeholderImage:options: + */ +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; + +/** + * Set the button `alternateImage` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the alternateImage. + * @param placeholder The alternateImage to be set initially, until the alternateImage request finishes. + * @param options The options to use when downloading the alternateImage. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; + +/** + * Set the button `alternateImage` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the alternateImage. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the alternateImage parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the alternateImage was retrieved from the local cache or from the network. + * The fourth parameter is the original alternateImage url. + */ +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the button `alternateImage` with an `url`, placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the alternateImage. + * @param placeholder The alternateImage to be set initially, until the alternateImage request finishes. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the alternateImage parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the alternateImage was retrieved from the local cache or from the network. + * The fourth parameter is the original alternateImage url. + */ +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; + +/** + * Set the button `alternateImage` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the alternateImage. + * @param placeholder The alternateImage to be set initially, until the alternateImage request finishes. + * @param options The options to use when downloading the alternateImage. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the alternateImage parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the alternateImage was retrieved from the local cache or from the network. + * The fourth parameter is the original alternateImage url. + */ +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the button `alternateImage` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the alternateImage. + * @param placeholder The alternateImage to be set initially, until the alternateImage request finishes. + * @param options The options to use when downloading the alternateImage. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while alternateImage is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the alternateImage parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the alternateImage was retrieved from the local cache or from the network. + * The fourth parameter is the original alternateImage url. + */ +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + +#pragma mark - Cancel + +/** + * Cancel the current image download + */ +- (void)sd_cancelCurrentImageLoad; + +/** + * Cancel the current alternateImage download + */ +- (void)sd_cancelCurrentAlternateImageLoad; + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/NSButton+WebCache.m b/Pods/SDWebImage/SDWebImage/NSButton+WebCache.m new file mode 100644 index 0000000..3ca080f --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/NSButton+WebCache.m @@ -0,0 +1,147 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "NSButton+WebCache.h" + +#if SD_MAC + +#import "objc/runtime.h" +#import "UIView+WebCacheOperation.h" +#import "UIView+WebCache.h" + +static inline NSString * imageOperationKey() { + return @"NSButtonImageOperation"; +} + +static inline NSString * alternateImageOperationKey() { + return @"NSButtonAlternateImageOperation"; +} + +@implementation NSButton (WebCache) + +#pragma mark - Image + +- (void)sd_setImageWithURL:(nullable NSURL *)url { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock { + self.sd_currentImageURL = url; + + __weak typeof(self)weakSelf = self; + [self sd_internalSetImageWithURL:url + placeholderImage:placeholder + options:options + operationKey:imageOperationKey() + setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) { + weakSelf.image = image; + } + progress:progressBlock + completed:completedBlock]; +} + +#pragma mark - Alternate Image + +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url { + [self sd_setAlternateImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; +} + +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder { + [self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; +} + +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; +} + +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setAlternateImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setAlternateImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; +} + +- (void)sd_setAlternateImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock { + self.sd_currentAlternateImageURL = url; + + __weak typeof(self)weakSelf = self; + [self sd_internalSetImageWithURL:url + placeholderImage:placeholder + options:options + operationKey:alternateImageOperationKey() + setImageBlock:^(NSImage * _Nullable image, NSData * _Nullable imageData) { + weakSelf.alternateImage = image; + } + progress:progressBlock + completed:completedBlock]; +} + +#pragma mark - Cancel + +- (void)sd_cancelCurrentImageLoad { + [self sd_cancelImageLoadOperationWithKey:imageOperationKey()]; +} + +- (void)sd_cancelCurrentAlternateImageLoad { + [self sd_cancelImageLoadOperationWithKey:alternateImageOperationKey()]; +} + +#pragma mar - Private + +- (NSURL *)sd_currentImageURL { + return objc_getAssociatedObject(self, @selector(sd_currentImageURL)); +} + +- (void)setSd_currentImageURL:(NSURL *)sd_currentImageURL { + objc_setAssociatedObject(self, @selector(sd_currentImageURL), sd_currentImageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (NSURL *)sd_currentAlternateImageURL { + return objc_getAssociatedObject(self, @selector(sd_currentAlternateImageURL)); +} + +- (void)setSd_currentAlternateImageURL:(NSURL *)sd_currentAlternateImageURL { + objc_setAssociatedObject(self, @selector(sd_currentAlternateImageURL), sd_currentAlternateImageURL, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.h b/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.h new file mode 100644 index 0000000..d29bbad --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.h @@ -0,0 +1,51 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Fabrice Aneche + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +typedef NS_ENUM(NSInteger, SDImageFormat) { + SDImageFormatUndefined = -1, + SDImageFormatJPEG = 0, + SDImageFormatPNG, + SDImageFormatGIF, + SDImageFormatTIFF, + SDImageFormatWebP, + SDImageFormatHEIC, + SDImageFormatHEIF +}; + +@interface NSData (ImageContentType) + +/** + * Return image format + * + * @param data the input image data + * + * @return the image format as `SDImageFormat` (enum) + */ ++ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data; + +/** + * Convert SDImageFormat to UTType + * + * @param format Format as SDImageFormat + * @return The UTType as CFStringRef + */ ++ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format; + +/** + * Convert UTTyppe to SDImageFormat + * + * @param uttype The UTType as CFStringRef + * @return The Format as SDImageFormat + */ ++ (SDImageFormat)sd_imageFormatFromUTType:(nonnull CFStringRef)uttype; + +@end diff --git a/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.m b/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.m new file mode 100644 index 0000000..927330c --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/NSData+ImageContentType.m @@ -0,0 +1,130 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Fabrice Aneche + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "NSData+ImageContentType.h" +#if SD_MAC +#import +#else +#import +#endif + +// Currently Image/IO does not support WebP +#define kSDUTTypeWebP ((__bridge CFStringRef)@"public.webp") +// AVFileTypeHEIC/AVFileTypeHEIF is defined in AVFoundation via iOS 11, we use this without import AVFoundation +#define kSDUTTypeHEIC ((__bridge CFStringRef)@"public.heic") +#define kSDUTTypeHEIF ((__bridge CFStringRef)@"public.heif") + +@implementation NSData (ImageContentType) + ++ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data { + if (!data) { + return SDImageFormatUndefined; + } + + // File signatures table: http://www.garykessler.net/library/file_sigs.html + uint8_t c; + [data getBytes:&c length:1]; + switch (c) { + case 0xFF: + return SDImageFormatJPEG; + case 0x89: + return SDImageFormatPNG; + case 0x47: + return SDImageFormatGIF; + case 0x49: + case 0x4D: + return SDImageFormatTIFF; + case 0x52: { + if (data.length >= 12) { + //RIFF....WEBP + NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding]; + if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) { + return SDImageFormatWebP; + } + } + break; + } + case 0x00: { + if (data.length >= 12) { + //....ftypheic ....ftypheix ....ftyphevc ....ftyphevx + NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(4, 8)] encoding:NSASCIIStringEncoding]; + if ([testString isEqualToString:@"ftypheic"] + || [testString isEqualToString:@"ftypheix"] + || [testString isEqualToString:@"ftyphevc"] + || [testString isEqualToString:@"ftyphevx"]) { + return SDImageFormatHEIC; + } + if ([testString isEqualToString:@"ftypmif1"] || [testString isEqualToString:@"ftypmsf1"]) { + return SDImageFormatHEIF; + } + } + break; + } + } + return SDImageFormatUndefined; +} + ++ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format { + CFStringRef UTType; + switch (format) { + case SDImageFormatJPEG: + UTType = kUTTypeJPEG; + break; + case SDImageFormatPNG: + UTType = kUTTypePNG; + break; + case SDImageFormatGIF: + UTType = kUTTypeGIF; + break; + case SDImageFormatTIFF: + UTType = kUTTypeTIFF; + break; + case SDImageFormatWebP: + UTType = kSDUTTypeWebP; + break; + case SDImageFormatHEIC: + UTType = kSDUTTypeHEIC; + break; + case SDImageFormatHEIF: + UTType = kSDUTTypeHEIF; + break; + default: + // default is kUTTypePNG + UTType = kUTTypePNG; + break; + } + return UTType; +} + ++ (SDImageFormat)sd_imageFormatFromUTType:(CFStringRef)uttype { + if (!uttype) { + return SDImageFormatUndefined; + } + SDImageFormat imageFormat; + if (CFStringCompare(uttype, kUTTypeJPEG, 0) == kCFCompareEqualTo) { + imageFormat = SDImageFormatJPEG; + } else if (CFStringCompare(uttype, kUTTypePNG, 0) == kCFCompareEqualTo) { + imageFormat = SDImageFormatPNG; + } else if (CFStringCompare(uttype, kUTTypeGIF, 0) == kCFCompareEqualTo) { + imageFormat = SDImageFormatGIF; + } else if (CFStringCompare(uttype, kUTTypeTIFF, 0) == kCFCompareEqualTo) { + imageFormat = SDImageFormatTIFF; + } else if (CFStringCompare(uttype, kSDUTTypeWebP, 0) == kCFCompareEqualTo) { + imageFormat = SDImageFormatWebP; + } else if (CFStringCompare(uttype, kSDUTTypeHEIC, 0) == kCFCompareEqualTo) { + imageFormat = SDImageFormatHEIC; + } else if (CFStringCompare(uttype, kSDUTTypeHEIF, 0) == kCFCompareEqualTo) { + imageFormat = SDImageFormatHEIF; + } else { + imageFormat = SDImageFormatUndefined; + } + return imageFormat; +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/NSImage+WebCache.h b/Pods/SDWebImage/SDWebImage/NSImage+WebCache.h new file mode 100644 index 0000000..7515d40 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/NSImage+WebCache.h @@ -0,0 +1,23 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +#if SD_MAC + +#import + +@interface NSImage (WebCache) + +- (CGImageRef)CGImage; +- (NSArray *)images; +- (BOOL)isGIF; + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/NSImage+WebCache.m b/Pods/SDWebImage/SDWebImage/NSImage+WebCache.m new file mode 100644 index 0000000..140ed6c --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/NSImage+WebCache.m @@ -0,0 +1,41 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "NSImage+WebCache.h" + +#if SD_MAC + +@implementation NSImage (WebCache) + +- (CGImageRef)CGImage { + NSRect imageRect = NSMakeRect(0, 0, self.size.width, self.size.height); + CGImageRef cgImage = [self CGImageForProposedRect:&imageRect context:NULL hints:nil]; + return cgImage; +} + +- (NSArray *)images { + return nil; +} + +- (BOOL)isGIF { + BOOL isGIF = NO; + for (NSImageRep *rep in self.representations) { + if ([rep isKindOfClass:[NSBitmapImageRep class]]) { + NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; + NSUInteger frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue]; + isGIF = frameCount > 1 ? YES : NO; + break; + } + } + return isGIF; +} + +@end + +#endif + diff --git a/Pods/SDWebImage/SDWebImage/SDAnimatedImageRep.h b/Pods/SDWebImage/SDWebImage/SDAnimatedImageRep.h new file mode 100644 index 0000000..c794c4b --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDAnimatedImageRep.h @@ -0,0 +1,20 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +#if SD_MAC + +// A subclass of `NSBitmapImageRep` to fix that GIF loop count issue because `NSBitmapImageRep` will reset `NSImageCurrentFrameDuration` by using `kCGImagePropertyGIFDelayTime` but not `kCGImagePropertyGIFUnclampedDelayTime`. +// Built in GIF coder use this instead of `NSBitmapImageRep` for better GIF rendering. If you do not want this, only enable `SDWebImageImageIOCoder`, which just call `NSImage` API and actually use `NSBitmapImageRep` for GIF image. + +@interface SDAnimatedImageRep : NSBitmapImageRep + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/SDAnimatedImageRep.m b/Pods/SDWebImage/SDWebImage/SDAnimatedImageRep.m new file mode 100644 index 0000000..40e5785 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDAnimatedImageRep.m @@ -0,0 +1,81 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDAnimatedImageRep.h" + +#if SD_MAC + +#import "SDWebImageGIFCoder.h" + +@interface SDWebImageGIFCoder () + +- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source; + +@end + +@implementation SDAnimatedImageRep { + CGImageSourceRef _imageSource; +} + +- (void)dealloc { + if (_imageSource) { + CFRelease(_imageSource); + _imageSource = NULL; + } +} + +// `NSBitmapImageRep`'s `imageRepWithData:` is not designed initlizer ++ (instancetype)imageRepWithData:(NSData *)data { + SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:data]; + return imageRep; +} + +// We should override init method for `NSBitmapImageRep` to do initlize about animated image format +- (instancetype)initWithData:(NSData *)data { + self = [super initWithData:data]; + if (self) { + CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef) data, NULL); + if (!imageSource) { + return self; + } + _imageSource = imageSource; + } + return self; +} + +// `NSBitmapImageRep` will use `kCGImagePropertyGIFDelayTime` whenever you call `setProperty:withValue:` with `NSImageCurrentFrame` to change the current frame. We override it and use the actual `kCGImagePropertyGIFUnclampedDelayTime` if need. +- (void)setProperty:(NSBitmapImageRepPropertyKey)property withValue:(id)value { + [super setProperty:property withValue:value]; + if ([property isEqualToString:NSImageCurrentFrame]) { + // Access the image source + CGImageSourceRef imageSource = _imageSource; + if (!imageSource) { + return; + } + // Check format type + CFStringRef type = CGImageSourceGetType(imageSource); + if (!type) { + return; + } + NSUInteger index = [value unsignedIntegerValue]; + float frameDuration = 0; + // Through we currently process GIF only, in the 5.x we support APNG so we keep the extensibility + if (CFStringCompare(type, kUTTypeGIF, 0) == kCFCompareEqualTo) { + frameDuration = [[SDWebImageGIFCoder sharedCoder] sd_frameDurationAtIndex:index source:imageSource]; + } + if (!frameDuration) { + return; + } + // Reset super frame duration with the actual frame duration + [super setProperty:NSImageCurrentFrameDuration withValue:@(frameDuration)]; + } +} + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/SDImageCache.h b/Pods/SDWebImage/SDWebImage/SDImageCache.h new file mode 100644 index 0000000..ce25989 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDImageCache.h @@ -0,0 +1,310 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" +#import "SDImageCacheConfig.h" + +typedef NS_ENUM(NSInteger, SDImageCacheType) { + /** + * The image wasn't available the SDWebImage caches, but was downloaded from the web. + */ + SDImageCacheTypeNone, + /** + * The image was obtained from the disk cache. + */ + SDImageCacheTypeDisk, + /** + * The image was obtained from the memory cache. + */ + SDImageCacheTypeMemory +}; + +typedef NS_OPTIONS(NSUInteger, SDImageCacheOptions) { + /** + * By default, we do not query disk data when the image is cached in memory. This mask can force to query disk data at the same time. + */ + SDImageCacheQueryDataWhenInMemory = 1 << 0, + /** + * By default, we query the memory cache synchronously, disk cache asynchronously. This mask can force to query disk cache synchronously. + */ + SDImageCacheQueryDiskSync = 1 << 1, + /** + * By default, images are decoded respecting their original size. On iOS, this flag will scale down the + * images to a size compatible with the constrained memory of devices. + */ + SDImageCacheScaleDownLargeImages = 1 << 2 +}; + +typedef void(^SDCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType); + +typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache); + +typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); + + +/** + * SDImageCache maintains a memory cache and an optional disk cache. Disk cache write operations are performed + * asynchronous so it doesn’t add unnecessary latency to the UI. + */ +@interface SDImageCache : NSObject + +#pragma mark - Properties + +/** + * Cache Config object - storing all kind of settings + */ +@property (nonatomic, nonnull, readonly) SDImageCacheConfig *config; + +/** + * The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory. + */ +@property (assign, nonatomic) NSUInteger maxMemoryCost; + +/** + * The maximum number of objects the cache should hold. + */ +@property (assign, nonatomic) NSUInteger maxMemoryCountLimit; + +#pragma mark - Singleton and initialization + +/** + * Returns global shared cache instance + * + * @return SDImageCache global instance + */ ++ (nonnull instancetype)sharedImageCache; + +/** + * Init a new cache store with a specific namespace + * + * @param ns The namespace to use for this cache store + */ +- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns; + +/** + * Init a new cache store with a specific namespace and directory + * + * @param ns The namespace to use for this cache store + * @param directory Directory to cache disk images in + */ +- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns + diskCacheDirectory:(nonnull NSString *)directory NS_DESIGNATED_INITIALIZER; + +#pragma mark - Cache paths + +- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace; + +/** + * Add a read-only cache path to search for images pre-cached by SDImageCache + * Useful if you want to bundle pre-loaded images with your app + * + * @param path The path to use for this read-only cache path + */ +- (void)addReadOnlyCachePath:(nonnull NSString *)path; + +#pragma mark - Store Ops + +/** + * Asynchronously store an image into memory and disk cache at the given key. + * + * @param image The image to store + * @param key The unique image cache key, usually it's image absolute URL + * @param completionBlock A block executed after the operation is finished + */ +- (void)storeImage:(nullable UIImage *)image + forKey:(nullable NSString *)key + completion:(nullable SDWebImageNoParamsBlock)completionBlock; + +/** + * Asynchronously store an image into memory and disk cache at the given key. + * + * @param image The image to store + * @param key The unique image cache key, usually it's image absolute URL + * @param toDisk Store the image to disk cache if YES + * @param completionBlock A block executed after the operation is finished + */ +- (void)storeImage:(nullable UIImage *)image + forKey:(nullable NSString *)key + toDisk:(BOOL)toDisk + completion:(nullable SDWebImageNoParamsBlock)completionBlock; + +/** + * Asynchronously store an image into memory and disk cache at the given key. + * + * @param image The image to store + * @param imageData The image data as returned by the server, this representation will be used for disk storage + * instead of converting the given image object into a storable/compressed image format in order + * to save quality and CPU + * @param key The unique image cache key, usually it's image absolute URL + * @param toDisk Store the image to disk cache if YES + * @param completionBlock A block executed after the operation is finished + */ +- (void)storeImage:(nullable UIImage *)image + imageData:(nullable NSData *)imageData + forKey:(nullable NSString *)key + toDisk:(BOOL)toDisk + completion:(nullable SDWebImageNoParamsBlock)completionBlock; + +/** + * Synchronously store image NSData into disk cache at the given key. + * + * + * @param imageData The image data to store + * @param key The unique image cache key, usually it's image absolute URL + */ +- (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key; + +#pragma mark - Query and Retrieve Ops + +/** + * Async check if image exists in disk cache already (does not load the image) + * + * @param key the key describing the url + * @param completionBlock the block to be executed when the check is done. + * @note the completion block will be always executed on the main queue + */ +- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock; + +/** + * Sync check if image data exists in disk cache already (does not load the image) + * + * @param key the key describing the url + */ +- (BOOL)diskImageDataExistsWithKey:(nullable NSString *)key; + +/** + * Query the image data for the given key synchronously. + * + * @param key The unique key used to store the wanted image + * @return The image data for the given key, or nil if not found. + */ +- (nullable NSData *)diskImageDataForKey:(nullable NSString *)key; + +/** + * Operation that queries the cache asynchronously and call the completion when done. + * + * @param key The unique key used to store the wanted image + * @param doneBlock The completion block. Will not get called if the operation is cancelled + * + * @return a NSOperation instance containing the cache op + */ +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key done:(nullable SDCacheQueryCompletedBlock)doneBlock; + +/** + * Operation that queries the cache asynchronously and call the completion when done. + * + * @param key The unique key used to store the wanted image + * @param options A mask to specify options to use for this cache query + * @param doneBlock The completion block. Will not get called if the operation is cancelled + * + * @return a NSOperation instance containing the cache op + */ +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock; + +/** + * Query the memory cache synchronously. + * + * @param key The unique key used to store the image + * @return The image for the given key, or nil if not found. + */ +- (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key; + +/** + * Query the disk cache synchronously. + * + * @param key The unique key used to store the image + * @return The image for the given key, or nil if not found. + */ +- (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key; + +/** + * Query the cache (memory and or disk) synchronously after checking the memory cache. + * + * @param key The unique key used to store the image + * @return The image for the given key, or nil if not found. + */ +- (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key; + +#pragma mark - Remove Ops + +/** + * Remove the image from memory and disk cache asynchronously + * + * @param key The unique image cache key + * @param completion A block that should be executed after the image has been removed (optional) + */ +- (void)removeImageForKey:(nullable NSString *)key withCompletion:(nullable SDWebImageNoParamsBlock)completion; + +/** + * Remove the image from memory and optionally disk cache asynchronously + * + * @param key The unique image cache key + * @param fromDisk Also remove cache entry from disk if YES + * @param completion A block that should be executed after the image has been removed (optional) + */ +- (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion; + +#pragma mark - Cache clean Ops + +/** + * Clear all memory cached images + */ +- (void)clearMemory; + +/** + * Async clear all disk cached images. Non-blocking method - returns immediately. + * @param completion A block that should be executed after cache expiration completes (optional) + */ +- (void)clearDiskOnCompletion:(nullable SDWebImageNoParamsBlock)completion; + +/** + * Async remove all expired cached image from disk. Non-blocking method - returns immediately. + * @param completionBlock A block that should be executed after cache expiration completes (optional) + */ +- (void)deleteOldFilesWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock; + +#pragma mark - Cache Info + +/** + * Get the size used by the disk cache + */ +- (NSUInteger)getSize; + +/** + * Get the number of images in the disk cache + */ +- (NSUInteger)getDiskCount; + +/** + * Asynchronously calculate the disk cache's size. + */ +- (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock; + +#pragma mark - Cache Paths + +/** + * Get the cache path for a certain key (needs the cache path root folder) + * + * @param key the key (can be obtained from url using cacheKeyForURL) + * @param path the cache path root folder + * + * @return the cache path + */ +- (nullable NSString *)cachePathForKey:(nullable NSString *)key inPath:(nonnull NSString *)path; + +/** + * Get the default cache path for a certain key + * + * @param key the key (can be obtained from url using cacheKeyForURL) + * + * @return the default cache path + */ +- (nullable NSString *)defaultCachePathForKey:(nullable NSString *)key; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDImageCache.m b/Pods/SDWebImage/SDWebImage/SDImageCache.m new file mode 100644 index 0000000..015f6ac --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDImageCache.m @@ -0,0 +1,813 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDImageCache.h" +#import +#import "NSImage+WebCache.h" +#import "UIImage+MemoryCacheCost.h" +#import "SDWebImageCodersManager.h" + +#define SD_MAX_FILE_EXTENSION_LENGTH (NAME_MAX - CC_MD5_DIGEST_LENGTH * 2 - 1) + +#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); +#define UNLOCK(lock) dispatch_semaphore_signal(lock); + +// A memory cache which auto purge the cache on memory warning and support weak cache. +@interface SDMemoryCache : NSCache + +@end + +// Private +@interface SDMemoryCache () + +@property (nonatomic, strong, nonnull) SDImageCacheConfig *config; +@property (nonatomic, strong, nonnull) NSMapTable *weakCache; // strong-weak cache +@property (nonatomic, strong, nonnull) dispatch_semaphore_t weakCacheLock; // a lock to keep the access to `weakCache` thread-safe + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithConfig:(nonnull SDImageCacheConfig *)config; + +@end + +@implementation SDMemoryCache + +// Current this seems no use on macOS (macOS use virtual memory and do not clear cache when memory warning). So we only override on iOS/tvOS platform. +// But in the future there may be more options and features for this subclass. +#if SD_UIKIT + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +} + +- (instancetype)initWithConfig:(SDImageCacheConfig *)config { + self = [super init]; + if (self) { + // Use a strong-weak maptable storing the secondary cache. Follow the doc that NSCache does not copy keys + // This is useful when the memory warning, the cache was purged. However, the image instance can be retained by other instance such as imageViews and alive. + // At this case, we can sync weak cache back and do not need to load from disk cache + self.weakCache = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0]; + self.weakCacheLock = dispatch_semaphore_create(1); + self.config = config; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didReceiveMemoryWarning:) + name:UIApplicationDidReceiveMemoryWarningNotification + object:nil]; + } + return self; +} + +- (void)didReceiveMemoryWarning:(NSNotification *)notification { + // Only remove cache, but keep weak cache + [super removeAllObjects]; +} + +// `setObject:forKey:` just call this with 0 cost. Override this is enough +- (void)setObject:(id)obj forKey:(id)key cost:(NSUInteger)g { + [super setObject:obj forKey:key cost:g]; + if (!self.config.shouldUseWeakMemoryCache) { + return; + } + if (key && obj) { + // Store weak cache + LOCK(self.weakCacheLock); + // Do the real copy of the key and only let NSMapTable manage the key's lifetime + // Fixes issue #2507 https://github.com/SDWebImage/SDWebImage/issues/2507 + [self.weakCache setObject:obj forKey:[[key mutableCopy] copy]]; + UNLOCK(self.weakCacheLock); + } +} + +- (id)objectForKey:(id)key { + id obj = [super objectForKey:key]; + if (!self.config.shouldUseWeakMemoryCache) { + return obj; + } + if (key && !obj) { + // Check weak cache + LOCK(self.weakCacheLock); + obj = [self.weakCache objectForKey:key]; + UNLOCK(self.weakCacheLock); + if (obj) { + // Sync cache + NSUInteger cost = 0; + if ([obj isKindOfClass:[UIImage class]]) { + cost = [(UIImage *)obj sd_memoryCost]; + } + [super setObject:obj forKey:key cost:cost]; + } + } + return obj; +} + +- (void)removeObjectForKey:(id)key { + [super removeObjectForKey:key]; + if (!self.config.shouldUseWeakMemoryCache) { + return; + } + if (key) { + // Remove weak cache + LOCK(self.weakCacheLock); + [self.weakCache removeObjectForKey:key]; + UNLOCK(self.weakCacheLock); + } +} + +- (void)removeAllObjects { + [super removeAllObjects]; + if (!self.config.shouldUseWeakMemoryCache) { + return; + } + // Manually remove should also remove weak cache + LOCK(self.weakCacheLock); + [self.weakCache removeAllObjects]; + UNLOCK(self.weakCacheLock); +} + +#else + +- (instancetype)initWithConfig:(SDImageCacheConfig *)config { + self = [super init]; + return self; +} + +#endif + +@end + +@interface SDImageCache () + +#pragma mark - Properties +@property (strong, nonatomic, nonnull) SDMemoryCache *memCache; +@property (strong, nonatomic, nonnull) NSString *diskCachePath; +@property (strong, nonatomic, nullable) NSMutableArray *customPaths; +@property (strong, nonatomic, nullable) dispatch_queue_t ioQueue; +@property (strong, nonatomic, nonnull) NSFileManager *fileManager; + +@end + + +@implementation SDImageCache + +#pragma mark - Singleton, init, dealloc + ++ (nonnull instancetype)sharedImageCache { + static dispatch_once_t once; + static id instance; + dispatch_once(&once, ^{ + instance = [self new]; + }); + return instance; +} + +- (instancetype)init { + return [self initWithNamespace:@"default"]; +} + +- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns { + NSString *path = [self makeDiskCachePath:ns]; + return [self initWithNamespace:ns diskCacheDirectory:path]; +} + +- (nonnull instancetype)initWithNamespace:(nonnull NSString *)ns + diskCacheDirectory:(nonnull NSString *)directory { + if ((self = [super init])) { + NSString *fullNamespace = [@"com.hackemist.SDWebImageCache." stringByAppendingString:ns]; + + // Create IO serial queue + _ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL); + + _config = [[SDImageCacheConfig alloc] init]; + + // Init the memory cache + _memCache = [[SDMemoryCache alloc] initWithConfig:_config]; + _memCache.name = fullNamespace; + + // Init the disk cache + if (directory != nil) { + _diskCachePath = [directory stringByAppendingPathComponent:fullNamespace]; + } else { + NSString *path = [self makeDiskCachePath:ns]; + _diskCachePath = path; + } + + dispatch_sync(_ioQueue, ^{ + self.fileManager = [NSFileManager new]; + }); + +#if SD_UIKIT + // Subscribe to app events + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(deleteOldFiles) + name:UIApplicationWillTerminateNotification + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(backgroundDeleteOldFiles) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; +#endif + } + + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - Cache paths + +- (void)addReadOnlyCachePath:(nonnull NSString *)path { + if (!self.customPaths) { + self.customPaths = [NSMutableArray new]; + } + + if (![self.customPaths containsObject:path]) { + [self.customPaths addObject:path]; + } +} + +- (nullable NSString *)cachePathForKey:(nullable NSString *)key inPath:(nonnull NSString *)path { + NSString *filename = [self cachedFileNameForKey:key]; + return [path stringByAppendingPathComponent:filename]; +} + +- (nullable NSString *)defaultCachePathForKey:(nullable NSString *)key { + return [self cachePathForKey:key inPath:self.diskCachePath]; +} + +- (nullable NSString *)cachedFileNameForKey:(nullable NSString *)key { + const char *str = key.UTF8String; + if (str == NULL) { + str = ""; + } + unsigned char r[CC_MD5_DIGEST_LENGTH]; + CC_MD5(str, (CC_LONG)strlen(str), r); + NSURL *keyURL = [NSURL URLWithString:key]; + NSString *ext = keyURL ? keyURL.pathExtension : key.pathExtension; + // File system has file name length limit, we need to check if ext is too long, we don't add it to the filename + if (ext.length > SD_MAX_FILE_EXTENSION_LENGTH) { + ext = nil; + } + NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%@", + r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10], + r[11], r[12], r[13], r[14], r[15], ext.length == 0 ? @"" : [NSString stringWithFormat:@".%@", ext]]; + return filename; +} + +- (nullable NSString *)makeDiskCachePath:(nonnull NSString*)fullNamespace { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + return [paths[0] stringByAppendingPathComponent:fullNamespace]; +} + +#pragma mark - Store Ops + +- (void)storeImage:(nullable UIImage *)image + forKey:(nullable NSString *)key + completion:(nullable SDWebImageNoParamsBlock)completionBlock { + [self storeImage:image imageData:nil forKey:key toDisk:YES completion:completionBlock]; +} + +- (void)storeImage:(nullable UIImage *)image + forKey:(nullable NSString *)key + toDisk:(BOOL)toDisk + completion:(nullable SDWebImageNoParamsBlock)completionBlock { + [self storeImage:image imageData:nil forKey:key toDisk:toDisk completion:completionBlock]; +} + +- (void)storeImage:(nullable UIImage *)image + imageData:(nullable NSData *)imageData + forKey:(nullable NSString *)key + toDisk:(BOOL)toDisk + completion:(nullable SDWebImageNoParamsBlock)completionBlock { + if (!image || !key) { + if (completionBlock) { + completionBlock(); + } + return; + } + // if memory cache is enabled + if (self.config.shouldCacheImagesInMemory) { + NSUInteger cost = image.sd_memoryCost; + [self.memCache setObject:image forKey:key cost:cost]; + } + + if (toDisk) { + dispatch_async(self.ioQueue, ^{ + @autoreleasepool { + NSData *data = imageData; + if (!data && image) { + // If we do not have any data to detect image format, check whether it contains alpha channel to use PNG or JPEG format + SDImageFormat format; + if (SDCGImageRefContainsAlpha(image.CGImage)) { + format = SDImageFormatPNG; + } else { + format = SDImageFormatJPEG; + } + data = [[SDWebImageCodersManager sharedInstance] encodedDataWithImage:image format:format]; + } + [self _storeImageDataToDisk:data forKey:key]; + } + + if (completionBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(); + }); + } + }); + } else { + if (completionBlock) { + completionBlock(); + } + } +} + +- (void)storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key { + if (!imageData || !key) { + return; + } + dispatch_sync(self.ioQueue, ^{ + [self _storeImageDataToDisk:imageData forKey:key]; + }); +} + +// Make sure to call form io queue by caller +- (void)_storeImageDataToDisk:(nullable NSData *)imageData forKey:(nullable NSString *)key { + if (!imageData || !key) { + return; + } + + if (![self.fileManager fileExistsAtPath:_diskCachePath]) { + [self.fileManager createDirectoryAtPath:_diskCachePath withIntermediateDirectories:YES attributes:nil error:NULL]; + } + + // get cache Path for image key + NSString *cachePathForKey = [self defaultCachePathForKey:key]; + // transform to NSUrl + NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey]; + + [imageData writeToURL:fileURL options:self.config.diskCacheWritingOptions error:nil]; + + // disable iCloud backup + if (self.config.shouldDisableiCloud) { + [fileURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil]; + } +} + +#pragma mark - Query and Retrieve Ops + +- (void)diskImageExistsWithKey:(nullable NSString *)key completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock { + dispatch_async(self.ioQueue, ^{ + BOOL exists = [self _diskImageDataExistsWithKey:key]; + if (completionBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(exists); + }); + } + }); +} + +- (BOOL)diskImageDataExistsWithKey:(nullable NSString *)key { + if (!key) { + return NO; + } + __block BOOL exists = NO; + dispatch_sync(self.ioQueue, ^{ + exists = [self _diskImageDataExistsWithKey:key]; + }); + + return exists; +} + +// Make sure to call form io queue by caller +- (BOOL)_diskImageDataExistsWithKey:(nullable NSString *)key { + if (!key) { + return NO; + } + BOOL exists = [self.fileManager fileExistsAtPath:[self defaultCachePathForKey:key]]; + + // fallback because of https://github.com/SDWebImage/SDWebImage/pull/976 that added the extension to the disk file name + // checking the key with and without the extension + if (!exists) { + exists = [self.fileManager fileExistsAtPath:[self defaultCachePathForKey:key].stringByDeletingPathExtension]; + } + + return exists; +} + +- (nullable NSData *)diskImageDataForKey:(nullable NSString *)key { + if (!key) { + return nil; + } + __block NSData *imageData = nil; + dispatch_sync(self.ioQueue, ^{ + imageData = [self diskImageDataBySearchingAllPathsForKey:key]; + }); + + return imageData; +} + +- (nullable UIImage *)imageFromMemoryCacheForKey:(nullable NSString *)key { + return [self.memCache objectForKey:key]; +} + +- (nullable UIImage *)imageFromDiskCacheForKey:(nullable NSString *)key { + UIImage *diskImage = [self diskImageForKey:key]; + if (diskImage && self.config.shouldCacheImagesInMemory) { + NSUInteger cost = diskImage.sd_memoryCost; + [self.memCache setObject:diskImage forKey:key cost:cost]; + } + + return diskImage; +} + +- (nullable UIImage *)imageFromCacheForKey:(nullable NSString *)key { + // First check the in-memory cache... + UIImage *image = [self imageFromMemoryCacheForKey:key]; + if (image) { + return image; + } + + // Second check the disk cache... + image = [self imageFromDiskCacheForKey:key]; + return image; +} + +- (nullable NSData *)diskImageDataBySearchingAllPathsForKey:(nullable NSString *)key { + NSString *defaultPath = [self defaultCachePathForKey:key]; + NSData *data = [NSData dataWithContentsOfFile:defaultPath options:self.config.diskCacheReadingOptions error:nil]; + if (data) { + return data; + } + + // fallback because of https://github.com/SDWebImage/SDWebImage/pull/976 that added the extension to the disk file name + // checking the key with and without the extension + data = [NSData dataWithContentsOfFile:defaultPath.stringByDeletingPathExtension options:self.config.diskCacheReadingOptions error:nil]; + if (data) { + return data; + } + + NSArray *customPaths = [self.customPaths copy]; + for (NSString *path in customPaths) { + NSString *filePath = [self cachePathForKey:key inPath:path]; + NSData *imageData = [NSData dataWithContentsOfFile:filePath options:self.config.diskCacheReadingOptions error:nil]; + if (imageData) { + return imageData; + } + + // fallback because of https://github.com/SDWebImage/SDWebImage/pull/976 that added the extension to the disk file name + // checking the key with and without the extension + imageData = [NSData dataWithContentsOfFile:filePath.stringByDeletingPathExtension options:self.config.diskCacheReadingOptions error:nil]; + if (imageData) { + return imageData; + } + } + + return nil; +} + +- (nullable UIImage *)diskImageForKey:(nullable NSString *)key { + NSData *data = [self diskImageDataForKey:key]; + return [self diskImageForKey:key data:data]; +} + +- (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data { + return [self diskImageForKey:key data:data options:0]; +} + +- (nullable UIImage *)diskImageForKey:(nullable NSString *)key data:(nullable NSData *)data options:(SDImageCacheOptions)options { + if (data) { + UIImage *image = [[SDWebImageCodersManager sharedInstance] decodedImageWithData:data]; + image = [self scaledImageForKey:key image:image]; + if (self.config.shouldDecompressImages) { + BOOL shouldScaleDown = options & SDImageCacheScaleDownLargeImages; + image = [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&data options:@{SDWebImageCoderScaleDownLargeImagesKey: @(shouldScaleDown)}]; + } + return image; + } else { + return nil; + } +} + +- (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image { + return SDScaledImageForKey(key, image); +} + +- (NSOperation *)queryCacheOperationForKey:(NSString *)key done:(SDCacheQueryCompletedBlock)doneBlock { + return [self queryCacheOperationForKey:key options:0 done:doneBlock]; +} + +- (nullable NSOperation *)queryCacheOperationForKey:(nullable NSString *)key options:(SDImageCacheOptions)options done:(nullable SDCacheQueryCompletedBlock)doneBlock { + if (!key) { + if (doneBlock) { + doneBlock(nil, nil, SDImageCacheTypeNone); + } + return nil; + } + + // First check the in-memory cache... + UIImage *image = [self imageFromMemoryCacheForKey:key]; + BOOL shouldQueryMemoryOnly = (image && !(options & SDImageCacheQueryDataWhenInMemory)); + if (shouldQueryMemoryOnly) { + if (doneBlock) { + doneBlock(image, nil, SDImageCacheTypeMemory); + } + return nil; + } + + NSOperation *operation = [NSOperation new]; + void(^queryDiskBlock)(void) = ^{ + if (operation.isCancelled) { + // do not call the completion if cancelled + return; + } + + @autoreleasepool { + NSData *diskData = [self diskImageDataBySearchingAllPathsForKey:key]; + UIImage *diskImage; + SDImageCacheType cacheType = SDImageCacheTypeNone; + if (image) { + // the image is from in-memory cache + diskImage = image; + cacheType = SDImageCacheTypeMemory; + } else if (diskData) { + cacheType = SDImageCacheTypeDisk; + // decode image data only if in-memory cache missed + diskImage = [self diskImageForKey:key data:diskData options:options]; + if (diskImage && self.config.shouldCacheImagesInMemory) { + NSUInteger cost = diskImage.sd_memoryCost; + [self.memCache setObject:diskImage forKey:key cost:cost]; + } + } + + if (doneBlock) { + if (options & SDImageCacheQueryDiskSync) { + doneBlock(diskImage, diskData, cacheType); + } else { + dispatch_async(dispatch_get_main_queue(), ^{ + doneBlock(diskImage, diskData, cacheType); + }); + } + } + } + }; + + if (options & SDImageCacheQueryDiskSync) { + queryDiskBlock(); + } else { + dispatch_async(self.ioQueue, queryDiskBlock); + } + + return operation; +} + +#pragma mark - Remove Ops + +- (void)removeImageForKey:(nullable NSString *)key withCompletion:(nullable SDWebImageNoParamsBlock)completion { + [self removeImageForKey:key fromDisk:YES withCompletion:completion]; +} + +- (void)removeImageForKey:(nullable NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(nullable SDWebImageNoParamsBlock)completion { + if (key == nil) { + return; + } + + if (self.config.shouldCacheImagesInMemory) { + [self.memCache removeObjectForKey:key]; + } + + if (fromDisk) { + dispatch_async(self.ioQueue, ^{ + [self.fileManager removeItemAtPath:[self defaultCachePathForKey:key] error:nil]; + + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(); + }); + } + }); + } else if (completion){ + completion(); + } + +} + +# pragma mark - Mem Cache settings + +- (void)setMaxMemoryCost:(NSUInteger)maxMemoryCost { + self.memCache.totalCostLimit = maxMemoryCost; +} + +- (NSUInteger)maxMemoryCost { + return self.memCache.totalCostLimit; +} + +- (NSUInteger)maxMemoryCountLimit { + return self.memCache.countLimit; +} + +- (void)setMaxMemoryCountLimit:(NSUInteger)maxCountLimit { + self.memCache.countLimit = maxCountLimit; +} + +#pragma mark - Cache clean Ops + +- (void)clearMemory { + [self.memCache removeAllObjects]; +} + +- (void)clearDiskOnCompletion:(nullable SDWebImageNoParamsBlock)completion { + dispatch_async(self.ioQueue, ^{ + [self.fileManager removeItemAtPath:self.diskCachePath error:nil]; + [self.fileManager createDirectoryAtPath:self.diskCachePath + withIntermediateDirectories:YES + attributes:nil + error:NULL]; + + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(); + }); + } + }); +} + +- (void)deleteOldFiles { + [self deleteOldFilesWithCompletionBlock:nil]; +} + +- (void)deleteOldFilesWithCompletionBlock:(nullable SDWebImageNoParamsBlock)completionBlock { + dispatch_async(self.ioQueue, ^{ + NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; + + // Compute content date key to be used for tests + NSURLResourceKey cacheContentDateKey = NSURLContentModificationDateKey; + switch (self.config.diskCacheExpireType) { + case SDImageCacheConfigExpireTypeAccessDate: + cacheContentDateKey = NSURLContentAccessDateKey; + break; + + case SDImageCacheConfigExpireTypeModificationDate: + cacheContentDateKey = NSURLContentModificationDateKey; + break; + + default: + break; + } + + NSArray *resourceKeys = @[NSURLIsDirectoryKey, cacheContentDateKey, NSURLTotalFileAllocatedSizeKey]; + + // This enumerator prefetches useful properties for our cache files. + NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtURL:diskCacheURL + includingPropertiesForKeys:resourceKeys + options:NSDirectoryEnumerationSkipsHiddenFiles + errorHandler:NULL]; + + NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:-self.config.maxCacheAge]; + NSMutableDictionary *> *cacheFiles = [NSMutableDictionary dictionary]; + NSUInteger currentCacheSize = 0; + + // Enumerate all of the files in the cache directory. This loop has two purposes: + // + // 1. Removing files that are older than the expiration date. + // 2. Storing file attributes for the size-based cleanup pass. + NSMutableArray *urlsToDelete = [[NSMutableArray alloc] init]; + for (NSURL *fileURL in fileEnumerator) { + NSError *error; + NSDictionary *resourceValues = [fileURL resourceValuesForKeys:resourceKeys error:&error]; + + // Skip directories and errors. + if (error || !resourceValues || [resourceValues[NSURLIsDirectoryKey] boolValue]) { + continue; + } + + // Remove files that are older than the expiration date; + NSDate *modifiedDate = resourceValues[cacheContentDateKey]; + if ([[modifiedDate laterDate:expirationDate] isEqualToDate:expirationDate]) { + [urlsToDelete addObject:fileURL]; + continue; + } + + // Store a reference to this file and account for its total size. + NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; + currentCacheSize += totalAllocatedSize.unsignedIntegerValue; + cacheFiles[fileURL] = resourceValues; + } + + for (NSURL *fileURL in urlsToDelete) { + [self.fileManager removeItemAtURL:fileURL error:nil]; + } + + // If our remaining disk cache exceeds a configured maximum size, perform a second + // size-based cleanup pass. We delete the oldest files first. + if (self.config.maxCacheSize > 0 && currentCacheSize > self.config.maxCacheSize) { + // Target half of our maximum cache size for this cleanup pass. + const NSUInteger desiredCacheSize = self.config.maxCacheSize / 2; + + // Sort the remaining cache files by their last modification time or last access time (oldest first). + NSArray *sortedFiles = [cacheFiles keysSortedByValueWithOptions:NSSortConcurrent + usingComparator:^NSComparisonResult(id obj1, id obj2) { + return [obj1[cacheContentDateKey] compare:obj2[cacheContentDateKey]]; + }]; + + // Delete files until we fall below our desired cache size. + for (NSURL *fileURL in sortedFiles) { + if ([self.fileManager removeItemAtURL:fileURL error:nil]) { + NSDictionary *resourceValues = cacheFiles[fileURL]; + NSNumber *totalAllocatedSize = resourceValues[NSURLTotalFileAllocatedSizeKey]; + currentCacheSize -= totalAllocatedSize.unsignedIntegerValue; + + if (currentCacheSize < desiredCacheSize) { + break; + } + } + } + } + if (completionBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(); + }); + } + }); +} + +#if SD_UIKIT +- (void)backgroundDeleteOldFiles { + Class UIApplicationClass = NSClassFromString(@"UIApplication"); + if(!UIApplicationClass || ![UIApplicationClass respondsToSelector:@selector(sharedApplication)]) { + return; + } + UIApplication *application = [UIApplication performSelector:@selector(sharedApplication)]; + __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ + // Clean up any unfinished task business by marking where you + // stopped or ending the task outright. + [application endBackgroundTask:bgTask]; + bgTask = UIBackgroundTaskInvalid; + }]; + + // Start the long-running task and return immediately. + [self deleteOldFilesWithCompletionBlock:^{ + [application endBackgroundTask:bgTask]; + bgTask = UIBackgroundTaskInvalid; + }]; +} +#endif + +#pragma mark - Cache Info + +- (NSUInteger)getSize { + __block NSUInteger size = 0; + dispatch_sync(self.ioQueue, ^{ + NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtPath:self.diskCachePath]; + for (NSString *fileName in fileEnumerator) { + NSString *filePath = [self.diskCachePath stringByAppendingPathComponent:fileName]; + NSDictionary *attrs = [self.fileManager attributesOfItemAtPath:filePath error:nil]; + size += [attrs fileSize]; + } + }); + return size; +} + +- (NSUInteger)getDiskCount { + __block NSUInteger count = 0; + dispatch_sync(self.ioQueue, ^{ + NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtPath:self.diskCachePath]; + count = fileEnumerator.allObjects.count; + }); + return count; +} + +- (void)calculateSizeWithCompletionBlock:(nullable SDWebImageCalculateSizeBlock)completionBlock { + NSURL *diskCacheURL = [NSURL fileURLWithPath:self.diskCachePath isDirectory:YES]; + + dispatch_async(self.ioQueue, ^{ + NSUInteger fileCount = 0; + NSUInteger totalSize = 0; + + NSDirectoryEnumerator *fileEnumerator = [self.fileManager enumeratorAtURL:diskCacheURL + includingPropertiesForKeys:@[NSFileSize] + options:NSDirectoryEnumerationSkipsHiddenFiles + errorHandler:NULL]; + + for (NSURL *fileURL in fileEnumerator) { + NSNumber *fileSize; + [fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:NULL]; + totalSize += fileSize.unsignedIntegerValue; + fileCount += 1; + } + + if (completionBlock) { + dispatch_async(dispatch_get_main_queue(), ^{ + completionBlock(fileCount, totalSize); + }); + } + }); +} + +@end + diff --git a/Pods/SDWebImage/SDWebImage/SDImageCacheConfig.h b/Pods/SDWebImage/SDWebImage/SDImageCacheConfig.h new file mode 100644 index 0000000..c0de688 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDImageCacheConfig.h @@ -0,0 +1,79 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +typedef NS_ENUM(NSUInteger, SDImageCacheConfigExpireType) { + /** + * When the image is accessed it will update this value + */ + SDImageCacheConfigExpireTypeAccessDate, + /** + * The image was obtained from the disk cache (Default) + */ + SDImageCacheConfigExpireTypeModificationDate +}; + +@interface SDImageCacheConfig : NSObject + +/** + * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory. + * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. + */ +@property (assign, nonatomic) BOOL shouldDecompressImages; + +/** + * Whether or not to disable iCloud backup + * Defaults to YES. + */ +@property (assign, nonatomic) BOOL shouldDisableiCloud; + +/** + * Whether or not to use memory cache + * @note When the memory cache is disabled, the weak memory cache will also be disabled. + * Defaults to YES. + */ +@property (assign, nonatomic) BOOL shouldCacheImagesInMemory; + +/** + * The option to control weak memory cache for images. When enable, `SDImageCache`'s memory cache will use a weak maptable to store the image at the same time when it stored to memory, and get removed at the same time. + * However when memory warning is triggered, since the weak maptable does not hold a strong reference to image instacnce, even when the memory cache itself is purged, some images which are held strongly by UIImageViews or other live instances can be recovered again, to avoid later re-query from disk cache or network. This may be helpful for the case, for example, when app enter background and memory is purged, cause cell flashing after re-enter foreground. + * Defautls to YES. You can change this option dynamically. + */ +@property (assign, nonatomic) BOOL shouldUseWeakMemoryCache; + +/** + * The reading options while reading cache from disk. + * Defaults to 0. You can set this to `NSDataReadingMappedIfSafe` to improve performance. + */ +@property (assign, nonatomic) NSDataReadingOptions diskCacheReadingOptions; + +/** + * The writing options while writing cache to disk. + * Defaults to `NSDataWritingAtomic`. You can set this to `NSDataWritingWithoutOverwriting` to prevent overwriting an existing file. + */ +@property (assign, nonatomic) NSDataWritingOptions diskCacheWritingOptions; + +/** + * The maximum length of time to keep an image in the cache, in seconds. + */ +@property (assign, nonatomic) NSInteger maxCacheAge; + +/** + * The maximum size of the cache, in bytes. + */ +@property (assign, nonatomic) NSUInteger maxCacheSize; + +/** + * The attribute which the clear cache will be checked against when clearing the disk cache + * Default is Modified Date + */ +@property (assign, nonatomic) SDImageCacheConfigExpireType diskCacheExpireType; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDImageCacheConfig.m b/Pods/SDWebImage/SDWebImage/SDImageCacheConfig.m new file mode 100644 index 0000000..d4f4dd2 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDImageCacheConfig.m @@ -0,0 +1,30 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDImageCacheConfig.h" + +static const NSInteger kDefaultCacheMaxCacheAge = 60 * 60 * 24 * 7; // 1 week + +@implementation SDImageCacheConfig + +- (instancetype)init { + if (self = [super init]) { + _shouldDecompressImages = YES; + _shouldDisableiCloud = YES; + _shouldCacheImagesInMemory = YES; + _shouldUseWeakMemoryCache = YES; + _diskCacheReadingOptions = 0; + _diskCacheWritingOptions = NSDataWritingAtomic; + _maxCacheAge = kDefaultCacheMaxCacheAge; + _maxCacheSize = 0; + _diskCacheExpireType = SDImageCacheConfigExpireTypeModificationDate; + } + return self; +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageCoder.h b/Pods/SDWebImage/SDWebImage/SDWebImageCoder.h new file mode 100644 index 0000000..7c0a63f --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageCoder.h @@ -0,0 +1,119 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" +#import "NSData+ImageContentType.h" + +/** + A Boolean value indicating whether to scale down large images during decompressing. (NSNumber) + */ +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageCoderScaleDownLargeImagesKey; + +/** + Return the shared device-dependent RGB color space created with CGColorSpaceCreateDeviceRGB. + + @return The device-dependent RGB color space + */ +CG_EXTERN CGColorSpaceRef _Nonnull SDCGColorSpaceGetDeviceRGB(void); + +/** + Check whether CGImageRef contains alpha channel. + + @param imageRef The CGImageRef + @return Return YES if CGImageRef contains alpha channel, otherwise return NO + */ +CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef); + + +/** + This is the image coder protocol to provide custom image decoding/encoding. + These methods are all required to implement. + @note Pay attention that these methods are not called from main queue. + */ +@protocol SDWebImageCoder + +@required +#pragma mark - Decoding +/** + Returns YES if this coder can decode some data. Otherwise, the data should be passed to another coder. + + @param data The image data so we can look at it + @return YES if this coder can decode the data, NO otherwise + */ +- (BOOL)canDecodeFromData:(nullable NSData *)data; + +/** + Decode the image data to image. + + @param data The image data to be decoded + @return The decoded image from data + */ +- (nullable UIImage *)decodedImageWithData:(nullable NSData *)data; + +/** + Decompress the image with original image and image data. + + @param image The original image to be decompressed + @param data The pointer to original image data. The pointer itself is nonnull but image data can be null. This data will set to cache if needed. If you do not need to modify data at the sametime, ignore this param. + @param optionsDict A dictionary containing any decompressing options. Pass {SDWebImageCoderScaleDownLargeImagesKey: @(YES)} to scale down large images + @return The decompressed image + */ +- (nullable UIImage *)decompressedImageWithImage:(nullable UIImage *)image + data:(NSData * _Nullable * _Nonnull)data + options:(nullable NSDictionary*)optionsDict; + +#pragma mark - Encoding + +/** + Returns YES if this coder can encode some image. Otherwise, it should be passed to another coder. + + @param format The image format + @return YES if this coder can encode the image, NO otherwise + */ +- (BOOL)canEncodeToFormat:(SDImageFormat)format; + +/** + Encode the image to image data. + + @param image The image to be encoded + @param format The image format to encode, you should note `SDImageFormatUndefined` format is also possible + @return The encoded image data + */ +- (nullable NSData *)encodedDataWithImage:(nullable UIImage *)image format:(SDImageFormat)format; + +@end + + +/** + This is the image coder protocol to provide custom progressive image decoding. + These methods are all required to implement. + @note Pay attention that these methods are not called from main queue. + */ +@protocol SDWebImageProgressiveCoder + +@required +/** + Returns YES if this coder can incremental decode some data. Otherwise, it should be passed to another coder. + + @param data The image data so we can look at it + @return YES if this coder can decode the data, NO otherwise + */ +- (BOOL)canIncrementallyDecodeFromData:(nullable NSData *)data; + +/** + Incremental decode the image data to image. + + @param data The image data has been downloaded so far + @param finished Whether the download has finished + @warning because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts + @return The decoded image from data + */ +- (nullable UIImage *)incrementallyDecodedImageWithData:(nullable NSData *)data finished:(BOOL)finished; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageCoder.m b/Pods/SDWebImage/SDWebImage/SDWebImageCoder.m new file mode 100644 index 0000000..9357fe5 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageCoder.m @@ -0,0 +1,31 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCoder.h" + +NSString * const SDWebImageCoderScaleDownLargeImagesKey = @"scaleDownLargeImages"; + +CGColorSpaceRef SDCGColorSpaceGetDeviceRGB(void) { + static CGColorSpaceRef colorSpace; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + colorSpace = CGColorSpaceCreateDeviceRGB(); + }); + return colorSpace; +} + +BOOL SDCGImageRefContainsAlpha(CGImageRef imageRef) { + if (!imageRef) { + return NO; + } + CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); + BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone || + alphaInfo == kCGImageAlphaNoneSkipFirst || + alphaInfo == kCGImageAlphaNoneSkipLast); + return hasAlpha; +} diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageCoderHelper.h b/Pods/SDWebImage/SDWebImage/SDWebImageCoderHelper.h new file mode 100644 index 0000000..ad2fe85 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageCoderHelper.h @@ -0,0 +1,52 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" +#import "SDWebImageFrame.h" + +@interface SDWebImageCoderHelper : NSObject + +/** + Return an animated image with frames array. + For UIKit, this will apply the patch and then create animated UIImage. The patch is because that `+[UIImage animatedImageWithImages:duration:]` just use the average of duration for each image. So it will not work if different frame has different duration. Therefore we repeat the specify frame for specify times to let it work. + For AppKit, NSImage does not support animates other than GIF. This will try to encode the frames to GIF format and then create an animated NSImage for rendering. Attention the animated image may loss some detail if the input frames contain full alpha channel because GIF only supports 1 bit alpha channel. (For 1 pixel, either transparent or not) + + @param frames The frames array. If no frames or frames is empty, return nil + @return A animated image for rendering on UIImageView(UIKit) or NSImageView(AppKit) + */ ++ (UIImage * _Nullable)animatedImageWithFrames:(NSArray * _Nullable)frames; + +/** + Return frames array from an animated image. + For UIKit, this will unapply the patch for the description above and then create frames array. This will also work for normal animated UIImage. + For AppKit, NSImage does not support animates other than GIF. This will try to decode the GIF imageRep and then create frames array. + + @param animatedImage A animated image. If it's not animated, return nil + @return The frames array + */ ++ (NSArray * _Nullable)framesFromAnimatedImage:(UIImage * _Nullable)animatedImage; + +#if SD_UIKIT || SD_WATCH +/** + Convert an EXIF image orientation to an iOS one. + + @param exifOrientation EXIF orientation + @return iOS orientation + */ ++ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation; +/** + Convert an iOS orientation to an EXIF image orientation. + + @param imageOrientation iOS orientation + @return EXIF orientation + */ ++ (NSInteger)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation; +#endif + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageCoderHelper.m b/Pods/SDWebImage/SDWebImage/SDWebImageCoderHelper.m new file mode 100644 index 0000000..ea1dae1 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageCoderHelper.m @@ -0,0 +1,258 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCoderHelper.h" +#import "SDWebImageFrame.h" +#import "UIImage+MultiFormat.h" +#import "NSImage+WebCache.h" +#import +#import "SDAnimatedImageRep.h" + +@implementation SDWebImageCoderHelper + ++ (UIImage *)animatedImageWithFrames:(NSArray *)frames { + NSUInteger frameCount = frames.count; + if (frameCount == 0) { + return nil; + } + + UIImage *animatedImage; + +#if SD_UIKIT || SD_WATCH + NSUInteger durations[frameCount]; + for (size_t i = 0; i < frameCount; i++) { + durations[i] = frames[i].duration * 1000; + } + NSUInteger const gcd = gcdArray(frameCount, durations); + __block NSUInteger totalDuration = 0; + NSMutableArray *animatedImages = [NSMutableArray arrayWithCapacity:frameCount]; + [frames enumerateObjectsUsingBlock:^(SDWebImageFrame * _Nonnull frame, NSUInteger idx, BOOL * _Nonnull stop) { + UIImage *image = frame.image; + NSUInteger duration = frame.duration * 1000; + totalDuration += duration; + NSUInteger repeatCount; + if (gcd) { + repeatCount = duration / gcd; + } else { + repeatCount = 1; + } + for (size_t i = 0; i < repeatCount; ++i) { + [animatedImages addObject:image]; + } + }]; + + animatedImage = [UIImage animatedImageWithImages:animatedImages duration:totalDuration / 1000.f]; + +#else + + NSMutableData *imageData = [NSMutableData data]; + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF]; + // Create an image destination. GIF does not support EXIF image orientation + CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frameCount, NULL); + if (!imageDestination) { + // Handle failure. + return nil; + } + + for (size_t i = 0; i < frameCount; i++) { + @autoreleasepool { + SDWebImageFrame *frame = frames[i]; + float frameDuration = frame.duration; + CGImageRef frameImageRef = frame.image.CGImage; + NSDictionary *frameProperties = @{(__bridge NSString *)kCGImagePropertyGIFDictionary : @{(__bridge NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}}; + CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties); + } + } + // Finalize the destination. + if (CGImageDestinationFinalize(imageDestination) == NO) { + // Handle failure. + CFRelease(imageDestination); + return nil; + } + CFRelease(imageDestination); + SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:imageData]; + animatedImage = [[NSImage alloc] initWithSize:imageRep.size]; + [animatedImage addRepresentation:imageRep]; +#endif + + return animatedImage; +} + ++ (NSArray *)framesFromAnimatedImage:(UIImage *)animatedImage { + if (!animatedImage) { + return nil; + } + + NSMutableArray *frames = [NSMutableArray array]; + NSUInteger frameCount = 0; + +#if SD_UIKIT || SD_WATCH + NSArray *animatedImages = animatedImage.images; + frameCount = animatedImages.count; + if (frameCount == 0) { + return nil; + } + + NSTimeInterval avgDuration = animatedImage.duration / frameCount; + if (avgDuration == 0) { + avgDuration = 0.1; // if it's a animated image but no duration, set it to default 100ms (this do not have that 10ms limit like GIF or WebP to allow custom coder provide the limit) + } + + __block NSUInteger index = 0; + __block NSUInteger repeatCount = 1; + __block UIImage *previousImage = animatedImages.firstObject; + [animatedImages enumerateObjectsUsingBlock:^(UIImage * _Nonnull image, NSUInteger idx, BOOL * _Nonnull stop) { + // ignore first + if (idx == 0) { + return; + } + if ([image isEqual:previousImage]) { + repeatCount++; + } else { + SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount]; + [frames addObject:frame]; + repeatCount = 1; + index++; + } + previousImage = image; + // last one + if (idx == frameCount - 1) { + SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:previousImage duration:avgDuration * repeatCount]; + [frames addObject:frame]; + } + }]; + +#else + + NSBitmapImageRep *bitmapRep; + for (NSImageRep *imageRep in animatedImage.representations) { + if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) { + bitmapRep = (NSBitmapImageRep *)imageRep; + break; + } + } + if (bitmapRep) { + frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue]; + } + + if (frameCount == 0) { + return nil; + } + + for (size_t i = 0; i < frameCount; i++) { + @autoreleasepool { + // NSBitmapImageRep need to manually change frame. "Good taste" API + [bitmapRep setProperty:NSImageCurrentFrame withValue:@(i)]; + float frameDuration = [[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue]; + NSImage *frameImage = [[NSImage alloc] initWithCGImage:bitmapRep.CGImage size:CGSizeZero]; + SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:frameImage duration:frameDuration]; + [frames addObject:frame]; + } + } +#endif + + return frames; +} + +#if SD_UIKIT || SD_WATCH +// Convert an EXIF image orientation to an iOS one. ++ (UIImageOrientation)imageOrientationFromEXIFOrientation:(NSInteger)exifOrientation { + // CGImagePropertyOrientation is available on iOS 8 above. Currently kept for compatibility + UIImageOrientation imageOrientation = UIImageOrientationUp; + switch (exifOrientation) { + case 1: + imageOrientation = UIImageOrientationUp; + break; + case 3: + imageOrientation = UIImageOrientationDown; + break; + case 8: + imageOrientation = UIImageOrientationLeft; + break; + case 6: + imageOrientation = UIImageOrientationRight; + break; + case 2: + imageOrientation = UIImageOrientationUpMirrored; + break; + case 4: + imageOrientation = UIImageOrientationDownMirrored; + break; + case 5: + imageOrientation = UIImageOrientationLeftMirrored; + break; + case 7: + imageOrientation = UIImageOrientationRightMirrored; + break; + default: + break; + } + return imageOrientation; +} + +// Convert an iOS orientation to an EXIF image orientation. ++ (NSInteger)exifOrientationFromImageOrientation:(UIImageOrientation)imageOrientation { + // CGImagePropertyOrientation is available on iOS 8 above. Currently kept for compatibility + NSInteger exifOrientation = 1; + switch (imageOrientation) { + case UIImageOrientationUp: + exifOrientation = 1; + break; + case UIImageOrientationDown: + exifOrientation = 3; + break; + case UIImageOrientationLeft: + exifOrientation = 8; + break; + case UIImageOrientationRight: + exifOrientation = 6; + break; + case UIImageOrientationUpMirrored: + exifOrientation = 2; + break; + case UIImageOrientationDownMirrored: + exifOrientation = 4; + break; + case UIImageOrientationLeftMirrored: + exifOrientation = 5; + break; + case UIImageOrientationRightMirrored: + exifOrientation = 7; + break; + default: + break; + } + return exifOrientation; +} +#endif + +#pragma mark - Helper Fuction +#if SD_UIKIT || SD_WATCH +static NSUInteger gcd(NSUInteger a, NSUInteger b) { + NSUInteger c; + while (a != 0) { + c = a; + a = b % a; + b = c; + } + return b; +} + +static NSUInteger gcdArray(size_t const count, NSUInteger const * const values) { + if (count == 0) { + return 0; + } + NSUInteger result = values[0]; + for (size_t i = 1; i < count; ++i) { + result = gcd(values[i], result); + } + return result; +} +#endif + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageCodersManager.h b/Pods/SDWebImage/SDWebImage/SDWebImageCodersManager.h new file mode 100644 index 0000000..ca68748 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageCodersManager.h @@ -0,0 +1,58 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCoder.h" + +/** + Global object holding the array of coders, so that we avoid passing them from object to object. + Uses a priority queue behind scenes, which means the latest added coders have the highest priority. + This is done so when encoding/decoding something, we go through the list and ask each coder if they can handle the current data. + That way, users can add their custom coders while preserving our existing prebuilt ones + + Note: the `coders` getter will return the coders in their reversed order + Example: + - by default we internally set coders = `IOCoder`, `WebPCoder`. (`GIFCoder` is not recommended to add only if you want to get GIF support without `FLAnimatedImage`) + - calling `coders` will return `@[WebPCoder, IOCoder]` + - call `[addCoder:[MyCrazyCoder new]]` + - calling `coders` now returns `@[MyCrazyCoder, WebPCoder, IOCoder]` + + Coders + ------ + A coder must conform to the `SDWebImageCoder` protocol or even to `SDWebImageProgressiveCoder` if it supports progressive decoding + Conformance is important because that way, they will implement `canDecodeFromData` or `canEncodeToFormat` + Those methods are called on each coder in the array (using the priority order) until one of them returns YES. + That means that coder can decode that data / encode to that format + */ +@interface SDWebImageCodersManager : NSObject + +/** + Shared reusable instance + */ ++ (nonnull instancetype)sharedInstance; + +/** + All coders in coders manager. The coders array is a priority queue, which means the later added coder will have the highest priority + */ +@property (nonatomic, copy, readwrite, nullable) NSArray> *coders; + +/** + Add a new coder to the end of coders array. Which has the highest priority. + + @param coder coder + */ +- (void)addCoder:(nonnull id)coder; + +/** + Remove a coder in the coders array. + + @param coder coder + */ +- (void)removeCoder:(nonnull id)coder; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageCodersManager.m b/Pods/SDWebImage/SDWebImage/SDWebImageCodersManager.m new file mode 100644 index 0000000..883d1fd --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageCodersManager.m @@ -0,0 +1,148 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCodersManager.h" +#import "SDWebImageImageIOCoder.h" +#import "SDWebImageGIFCoder.h" +#ifdef SD_WEBP +#import "SDWebImageWebPCoder.h" +#endif +#import "UIImage+MultiFormat.h" + +#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); +#define UNLOCK(lock) dispatch_semaphore_signal(lock); + +@interface SDWebImageCodersManager () + +@property (nonatomic, strong, nonnull) dispatch_semaphore_t codersLock; + +@end + +@implementation SDWebImageCodersManager + ++ (nonnull instancetype)sharedInstance { + static dispatch_once_t once; + static id instance; + dispatch_once(&once, ^{ + instance = [self new]; + }); + return instance; +} + +- (instancetype)init { + if (self = [super init]) { + // initialize with default coders + NSMutableArray> *mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder]] mutableCopy]; +#ifdef SD_WEBP + [mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]]; +#endif + _coders = [mutableCoders copy]; + _codersLock = dispatch_semaphore_create(1); + } + return self; +} + +#pragma mark - Coder IO operations + +- (void)addCoder:(nonnull id)coder { + if (![coder conformsToProtocol:@protocol(SDWebImageCoder)]) { + return; + } + LOCK(self.codersLock); + NSMutableArray> *mutableCoders = [self.coders mutableCopy]; + if (!mutableCoders) { + mutableCoders = [NSMutableArray array]; + } + [mutableCoders addObject:coder]; + self.coders = [mutableCoders copy]; + UNLOCK(self.codersLock); +} + +- (void)removeCoder:(nonnull id)coder { + if (![coder conformsToProtocol:@protocol(SDWebImageCoder)]) { + return; + } + LOCK(self.codersLock); + NSMutableArray> *mutableCoders = [self.coders mutableCopy]; + [mutableCoders removeObject:coder]; + self.coders = [mutableCoders copy]; + UNLOCK(self.codersLock); +} + +#pragma mark - SDWebImageCoder +- (BOOL)canDecodeFromData:(NSData *)data { + LOCK(self.codersLock); + NSArray> *coders = self.coders; + UNLOCK(self.codersLock); + for (id coder in coders.reverseObjectEnumerator) { + if ([coder canDecodeFromData:data]) { + return YES; + } + } + return NO; +} + +- (BOOL)canEncodeToFormat:(SDImageFormat)format { + LOCK(self.codersLock); + NSArray> *coders = self.coders; + UNLOCK(self.codersLock); + for (id coder in coders.reverseObjectEnumerator) { + if ([coder canEncodeToFormat:format]) { + return YES; + } + } + return NO; +} + +- (UIImage *)decodedImageWithData:(NSData *)data { + LOCK(self.codersLock); + NSArray> *coders = self.coders; + UNLOCK(self.codersLock); + for (id coder in coders.reverseObjectEnumerator) { + if ([coder canDecodeFromData:data]) { + return [coder decodedImageWithData:data]; + } + } + return nil; +} + +- (UIImage *)decompressedImageWithImage:(UIImage *)image + data:(NSData *__autoreleasing _Nullable *)data + options:(nullable NSDictionary*)optionsDict { + if (!image) { + return nil; + } + LOCK(self.codersLock); + NSArray> *coders = self.coders; + UNLOCK(self.codersLock); + for (id coder in coders.reverseObjectEnumerator) { + if ([coder canDecodeFromData:*data]) { + UIImage *decompressedImage = [coder decompressedImageWithImage:image data:data options:optionsDict]; + decompressedImage.sd_imageFormat = image.sd_imageFormat; + return decompressedImage; + } + } + return nil; +} + +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format { + if (!image) { + return nil; + } + LOCK(self.codersLock); + NSArray> *coders = self.coders; + UNLOCK(self.codersLock); + for (id coder in coders.reverseObjectEnumerator) { + if ([coder canEncodeToFormat:format]) { + return [coder encodedDataWithImage:image format:format]; + } + } + return nil; +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageCompat.h b/Pods/SDWebImage/SDWebImage/SDWebImageCompat.h new file mode 100644 index 0000000..a4493ae --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageCompat.h @@ -0,0 +1,107 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Jamie Pinkham + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import + +#ifdef __OBJC_GC__ + #error SDWebImage does not support Objective-C Garbage Collection +#endif + +// Apple's defines from TargetConditionals.h are a bit weird. +// Seems like TARGET_OS_MAC is always defined (on all platforms). +// To determine if we are running on OSX, we can only rely on TARGET_OS_IPHONE=0 and all the other platforms +#if !TARGET_OS_IPHONE && !TARGET_OS_IOS && !TARGET_OS_TV && !TARGET_OS_WATCH + #define SD_MAC 1 +#else + #define SD_MAC 0 +#endif + +// iOS and tvOS are very similar, UIKit exists on both platforms +// Note: watchOS also has UIKit, but it's very limited +#if TARGET_OS_IOS || TARGET_OS_TV + #define SD_UIKIT 1 +#else + #define SD_UIKIT 0 +#endif + +#if TARGET_OS_IOS + #define SD_IOS 1 +#else + #define SD_IOS 0 +#endif + +#if TARGET_OS_TV + #define SD_TV 1 +#else + #define SD_TV 0 +#endif + +#if TARGET_OS_WATCH + #define SD_WATCH 1 +#else + #define SD_WATCH 0 +#endif + + +#if SD_MAC + #import + #ifndef UIImage + #define UIImage NSImage + #endif + #ifndef UIImageView + #define UIImageView NSImageView + #endif + #ifndef UIView + #define UIView NSView + #endif +#else + #if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 + #error SDWebImage doesn't support Deployment Target version < 5.0 + #endif + + #if SD_UIKIT + #import + #endif + #if SD_WATCH + #import + #ifndef UIView + #define UIView WKInterfaceObject + #endif + #ifndef UIImageView + #define UIImageView WKInterfaceImage + #endif + #endif +#endif + +#ifndef NS_ENUM +#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type +#endif + +#ifndef NS_OPTIONS +#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type +#endif + +FOUNDATION_EXPORT UIImage *SDScaledImageForKey(NSString *key, UIImage *image); + +typedef void(^SDWebImageNoParamsBlock)(void); + +FOUNDATION_EXPORT NSString *const SDWebImageErrorDomain; + +#ifndef dispatch_queue_async_safe +#define dispatch_queue_async_safe(queue, block)\ + if (dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL) == dispatch_queue_get_label(queue)) {\ + block();\ + } else {\ + dispatch_async(queue, block);\ + } +#endif + +#ifndef dispatch_main_async_safe +#define dispatch_main_async_safe(block) dispatch_queue_async_safe(dispatch_get_main_queue(), block) +#endif diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageCompat.m b/Pods/SDWebImage/SDWebImage/SDWebImageCompat.m new file mode 100644 index 0000000..ffde1d2 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageCompat.m @@ -0,0 +1,71 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "UIImage+MultiFormat.h" + +#if !__has_feature(objc_arc) + #error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag +#endif + +#if !OS_OBJECT_USE_OBJC + #error SDWebImage need ARC for dispatch object +#endif + +inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) { + if (!image) { + return nil; + } + +#if SD_MAC + return image; +#elif SD_UIKIT || SD_WATCH + if ((image.images).count > 0) { + NSMutableArray *scaledImages = [NSMutableArray array]; + + for (UIImage *tempImage in image.images) { + [scaledImages addObject:SDScaledImageForKey(key, tempImage)]; + } + + UIImage *animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration]; + if (animatedImage) { + animatedImage.sd_imageLoopCount = image.sd_imageLoopCount; + animatedImage.sd_imageFormat = image.sd_imageFormat; + } + return animatedImage; + } else { +#if SD_WATCH + if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) { +#elif SD_UIKIT + if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { +#endif + CGFloat scale = 1; + if (key.length >= 8) { + NSRange range = [key rangeOfString:@"@2x."]; + if (range.location != NSNotFound) { + scale = 2.0; + } + + range = [key rangeOfString:@"@3x."]; + if (range.location != NSNotFound) { + scale = 3.0; + } + } + + if (scale != image.scale) { + UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; + scaledImage.sd_imageFormat = image.sd_imageFormat; + image = scaledImage; + } + } + return image; + } +#endif +} + +NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain"; diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.h b/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.h new file mode 100644 index 0000000..1bee959 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.h @@ -0,0 +1,292 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" +#import "SDWebImageOperation.h" + +typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { + /** + * Put the download in the low queue priority and task priority. + */ + SDWebImageDownloaderLowPriority = 1 << 0, + + /** + * This flag enables progressive download, the image is displayed progressively during download as a browser would do. + */ + SDWebImageDownloaderProgressiveDownload = 1 << 1, + + /** + * By default, request prevent the use of NSURLCache. With this flag, NSURLCache + * is used with default policies. + */ + SDWebImageDownloaderUseNSURLCache = 1 << 2, + + /** + * Call completion block with nil image/imageData if the image was read from NSURLCache + * (to be combined with `SDWebImageDownloaderUseNSURLCache`). + */ + SDWebImageDownloaderIgnoreCachedResponse = 1 << 3, + + /** + * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for + * extra time in background to let the request finish. If the background task expires the operation will be cancelled. + */ + SDWebImageDownloaderContinueInBackground = 1 << 4, + + /** + * Handles cookies stored in NSHTTPCookieStore by setting + * NSMutableURLRequest.HTTPShouldHandleCookies = YES; + */ + SDWebImageDownloaderHandleCookies = 1 << 5, + + /** + * Enable to allow untrusted SSL certificates. + * Useful for testing purposes. Use with caution in production. + */ + SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6, + + /** + * Put the download in the high queue priority and task priority. + */ + SDWebImageDownloaderHighPriority = 1 << 7, + + /** + * Scale down the image + */ + SDWebImageDownloaderScaleDownLargeImages = 1 << 8, +}; + +typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { + /** + * Default value. All download operations will execute in queue style (first-in-first-out). + */ + SDWebImageDownloaderFIFOExecutionOrder, + + /** + * All download operations will execute in stack style (last-in-first-out). + */ + SDWebImageDownloaderLIFOExecutionOrder +}; + +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification; +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; + +typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL); + +typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished); + +typedef NSDictionary SDHTTPHeadersDictionary; +typedef NSMutableDictionary SDHTTPHeadersMutableDictionary; + +typedef SDHTTPHeadersDictionary * _Nullable (^SDWebImageDownloaderHeadersFilterBlock)(NSURL * _Nullable url, SDHTTPHeadersDictionary * _Nullable headers); + +/** + * A token associated with each download. Can be used to cancel a download + */ +@interface SDWebImageDownloadToken : NSObject + +/** + The download's URL. This should be readonly and you should not modify + */ +@property (nonatomic, strong, nullable) NSURL *url; +/** + The cancel token taken from `addHandlersForProgress:completed`. This should be readonly and you should not modify + @note use `-[SDWebImageDownloadToken cancel]` to cancel the token + */ +@property (nonatomic, strong, nullable) id downloadOperationCancelToken; + +@end + + +/** + * Asynchronous downloader dedicated and optimized for image loading. + */ +@interface SDWebImageDownloader : NSObject + +/** + * Decompressing images that are downloaded and cached can improve performance but can consume lot of memory. + * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. + */ +@property (assign, nonatomic) BOOL shouldDecompressImages; + +/** + * The maximum number of concurrent downloads + */ +@property (assign, nonatomic) NSInteger maxConcurrentDownloads; + +/** + * Shows the current amount of downloads that still need to be downloaded + */ +@property (readonly, nonatomic) NSUInteger currentDownloadCount; + +/** + * The timeout value (in seconds) for the download operation. Default: 15.0. + */ +@property (assign, nonatomic) NSTimeInterval downloadTimeout; + +/** + * The configuration in use by the internal NSURLSession. + * Mutating this object directly has no effect. + * + * @see createNewSessionWithConfiguration: + */ +@property (readonly, nonatomic, nonnull) NSURLSessionConfiguration *sessionConfiguration; + + +/** + * Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`. + */ +@property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder; + +/** + * Singleton method, returns the shared instance + * + * @return global shared instance of downloader class + */ ++ (nonnull instancetype)sharedDownloader; + +/** + * Set the default URL credential to be set for request operations. + */ +@property (strong, nonatomic, nullable) NSURLCredential *urlCredential; + +/** + * Set username + */ +@property (strong, nonatomic, nullable) NSString *username; + +/** + * Set password + */ +@property (strong, nonatomic, nullable) NSString *password; + +/** + * Set filter to pick headers for downloading image HTTP request. + * + * This block will be invoked for each downloading image request, returned + * NSDictionary will be used as headers in corresponding HTTP request. + */ +@property (nonatomic, copy, nullable) SDWebImageDownloaderHeadersFilterBlock headersFilter; + +/** + * Creates an instance of a downloader with specified session configuration. + * @note `timeoutIntervalForRequest` is going to be overwritten. + * @return new instance of downloader class + */ +- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration NS_DESIGNATED_INITIALIZER; + +/** + * Set a value for a HTTP header to be appended to each download HTTP request. + * + * @param value The value for the header field. Use `nil` value to remove the header. + * @param field The name of the header field to set. + */ +- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field; + +/** + * Returns the value of the specified HTTP header field. + * + * @return The value associated with the header field field, or `nil` if there is no corresponding header field. + */ +- (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field; + +/** + * Sets a subclass of `NSOperation` and conforms to `SDWebImageDownloaderOperationInterface`. + * Default is `SDWebImageDownloaderOperation`. + * Can be used each time SDWebImage constructs a request + * operation to download an image. + * + * @param operationClass The subclass of `NSOperation` and conforms to `SDWebImageDownloaderOperationInterface`. + * Default is `SDWebImageDownloaderOperation`, Passing `nil` will revert to `SDWebImageDownloaderOperation`. + */ +- (void)setOperationClass:(nullable Class)operationClass; + +/** + * Creates a SDWebImageDownloader async downloader instance with a given URL + * + * The delegate will be informed when the image is finish downloaded or an error has happen. + * + * @see SDWebImageDownloaderDelegate + * + * @param url The URL to the image to download + * @param completedBlock A block called once the download is completed. + * If the download succeeded, the image parameter is set, in case of error, + * error parameter is set with the error. The last parameter is always YES + * if SDWebImageDownloaderProgressiveDownload isn't use. With the + * SDWebImageDownloaderProgressiveDownload option, this block is called + * repeatedly with the partial image object and the finished argument set to NO + * before to be called a last time with the full image and finished argument + * set to YES. In case of error, the finished argument is always YES. + */ +- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; + +/** + * Creates a SDWebImageDownloader async downloader instance with a given URL + * + * The delegate will be informed when the image is finish downloaded or an error has happen. + * + * @see SDWebImageDownloaderDelegate + * + * @param url The URL to the image to download + * @param options The options to be used for this download + * @param progressBlock A block called repeatedly while the image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called once the download is completed. + * If the download succeeded, the image parameter is set, in case of error, + * error parameter is set with the error. The last parameter is always YES + * if SDWebImageDownloaderProgressiveDownload isn't use. With the + * SDWebImageDownloaderProgressiveDownload option, this block is called + * repeatedly with the partial image object and the finished argument set to NO + * before to be called a last time with the full image and finished argument + * set to YES. In case of error, the finished argument is always YES. + * + * @return A token (SDWebImageDownloadToken) that can be passed to -cancel: to cancel this operation + */ +- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url + options:(SDWebImageDownloaderOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; + +/** + * Cancels a download that was previously queued using -downloadImageWithURL:options:progress:completed: + * + * @param token The token received from -downloadImageWithURL:options:progress:completed: that should be canceled. + */ +- (void)cancel:(nullable SDWebImageDownloadToken *)token; + +/** + * Sets the download queue suspension state + */ +- (void)setSuspended:(BOOL)suspended; + +/** + * Cancels all download operations in the queue + */ +- (void)cancelAllDownloads; + +/** + * Forces SDWebImageDownloader to create and use a new NSURLSession that is + * initialized with the given configuration. + * @note All existing download operations in the queue will be cancelled. + * @note `timeoutIntervalForRequest` is going to be overwritten. + * + * @param sessionConfiguration The configuration to use for the new NSURLSession + */ +- (void)createNewSessionWithConfiguration:(nonnull NSURLSessionConfiguration *)sessionConfiguration; + +/** + * Invalidates the managed session, optionally canceling pending operations. + * @note If you use custom downloader instead of the shared downloader, you need call this method when you do not use it to avoid memory leak + * @param cancelPendingOperations Whether or not to cancel pending operations. + * @note Calling this method on the shared downloader has no effect. + */ +- (void)invalidateSessionAndCancel:(BOOL)cancelPendingOperations; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.m b/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.m new file mode 100644 index 0000000..12fb24d --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageDownloader.m @@ -0,0 +1,439 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageDownloader.h" +#import "SDWebImageDownloaderOperation.h" + +#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); +#define UNLOCK(lock) dispatch_semaphore_signal(lock); + +@interface SDWebImageDownloadToken () + +@property (nonatomic, weak, nullable) NSOperation *downloadOperation; + +@end + +@implementation SDWebImageDownloadToken + +- (void)cancel { + if (self.downloadOperation) { + SDWebImageDownloadToken *cancelToken = self.downloadOperationCancelToken; + if (cancelToken) { + [self.downloadOperation cancel:cancelToken]; + } + } +} + +@end + + +@interface SDWebImageDownloader () + +@property (strong, nonatomic, nonnull) NSOperationQueue *downloadQueue; +@property (weak, nonatomic, nullable) NSOperation *lastAddedOperation; +@property (assign, nonatomic, nullable) Class operationClass; +@property (strong, nonatomic, nonnull) NSMutableDictionary *> *URLOperations; +@property (strong, nonatomic, nullable) SDHTTPHeadersMutableDictionary *HTTPHeaders; +@property (strong, nonatomic, nonnull) dispatch_semaphore_t operationsLock; // a lock to keep the access to `URLOperations` thread-safe +@property (strong, nonatomic, nonnull) dispatch_semaphore_t headersLock; // a lock to keep the access to `HTTPHeaders` thread-safe + +// The session in which data tasks will run +@property (strong, nonatomic) NSURLSession *session; + +@end + +@implementation SDWebImageDownloader + ++ (void)initialize { + // Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator ) + // To use it, just add #import "SDNetworkActivityIndicator.h" in addition to the SDWebImage import + if (NSClassFromString(@"SDNetworkActivityIndicator")) { + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")]; +#pragma clang diagnostic pop + + // Remove observer in case it was previously added. + [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStartNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStopNotification object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:activityIndicator + selector:NSSelectorFromString(@"startActivity") + name:SDWebImageDownloadStartNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:activityIndicator + selector:NSSelectorFromString(@"stopActivity") + name:SDWebImageDownloadStopNotification object:nil]; + } +} + ++ (nonnull instancetype)sharedDownloader { + static dispatch_once_t once; + static id instance; + dispatch_once(&once, ^{ + instance = [self new]; + }); + return instance; +} + +- (nonnull instancetype)init { + return [self initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; +} + +- (nonnull instancetype)initWithSessionConfiguration:(nullable NSURLSessionConfiguration *)sessionConfiguration { + if ((self = [super init])) { + _operationClass = [SDWebImageDownloaderOperation class]; + _shouldDecompressImages = YES; + _executionOrder = SDWebImageDownloaderFIFOExecutionOrder; + _downloadQueue = [NSOperationQueue new]; + _downloadQueue.maxConcurrentOperationCount = 6; + _downloadQueue.name = @"com.hackemist.SDWebImageDownloader"; + _URLOperations = [NSMutableDictionary new]; + SDHTTPHeadersMutableDictionary *headerDictionary = [SDHTTPHeadersMutableDictionary dictionary]; + NSString *userAgent = nil; +#if SD_UIKIT + // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43 + userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]]; +#elif SD_WATCH + // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43 + userAgent = [NSString stringWithFormat:@"%@/%@ (%@; watchOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[WKInterfaceDevice currentDevice] model], [[WKInterfaceDevice currentDevice] systemVersion], [[WKInterfaceDevice currentDevice] screenScale]]; +#elif SD_MAC + userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]]; +#endif + if (userAgent) { + if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) { + NSMutableString *mutableUserAgent = [userAgent mutableCopy]; + if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) { + userAgent = mutableUserAgent; + } + } + headerDictionary[@"User-Agent"] = userAgent; + } +#ifdef SD_WEBP + headerDictionary[@"Accept"] = @"image/webp,image/*;q=0.8"; +#else + headerDictionary[@"Accept"] = @"image/*;q=0.8"; +#endif + _HTTPHeaders = headerDictionary; + _operationsLock = dispatch_semaphore_create(1); + _headersLock = dispatch_semaphore_create(1); + _downloadTimeout = 15.0; + + [self createNewSessionWithConfiguration:sessionConfiguration]; + } + return self; +} + +- (void)createNewSessionWithConfiguration:(NSURLSessionConfiguration *)sessionConfiguration { + [self cancelAllDownloads]; + + if (self.session) { + [self.session invalidateAndCancel]; + } + + sessionConfiguration.timeoutIntervalForRequest = self.downloadTimeout; + + /** + * Create the session for this task + * We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate + * method calls and completion handler calls. + */ + self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration + delegate:self + delegateQueue:nil]; +} + +- (void)invalidateSessionAndCancel:(BOOL)cancelPendingOperations { + if (self == [SDWebImageDownloader sharedDownloader]) { + return; + } + if (cancelPendingOperations) { + [self.session invalidateAndCancel]; + } else { + [self.session finishTasksAndInvalidate]; + } +} + +- (void)dealloc { + [self.session invalidateAndCancel]; + self.session = nil; + + [self.downloadQueue cancelAllOperations]; +} + +- (void)setValue:(nullable NSString *)value forHTTPHeaderField:(nullable NSString *)field { + LOCK(self.headersLock); + if (value) { + self.HTTPHeaders[field] = value; + } else { + [self.HTTPHeaders removeObjectForKey:field]; + } + UNLOCK(self.headersLock); +} + +- (nullable NSString *)valueForHTTPHeaderField:(nullable NSString *)field { + if (!field) { + return nil; + } + return [[self allHTTPHeaderFields] objectForKey:field]; +} + +- (nonnull SDHTTPHeadersDictionary *)allHTTPHeaderFields { + LOCK(self.headersLock); + SDHTTPHeadersDictionary *allHTTPHeaderFields = [self.HTTPHeaders copy]; + UNLOCK(self.headersLock); + return allHTTPHeaderFields; +} + +- (void)setMaxConcurrentDownloads:(NSInteger)maxConcurrentDownloads { + _downloadQueue.maxConcurrentOperationCount = maxConcurrentDownloads; +} + +- (NSUInteger)currentDownloadCount { + return _downloadQueue.operationCount; +} + +- (NSInteger)maxConcurrentDownloads { + return _downloadQueue.maxConcurrentOperationCount; +} + +- (NSURLSessionConfiguration *)sessionConfiguration { + return self.session.configuration; +} + +- (void)setOperationClass:(nullable Class)operationClass { + if (operationClass && [operationClass isSubclassOfClass:[NSOperation class]] && [operationClass conformsToProtocol:@protocol(SDWebImageDownloaderOperationInterface)]) { + _operationClass = operationClass; + } else { + _operationClass = [SDWebImageDownloaderOperation class]; + } +} + +- (NSOperation *)createDownloaderOperationWithUrl:(nullable NSURL *)url + options:(SDWebImageDownloaderOptions)options { + NSTimeInterval timeoutInterval = self.downloadTimeout; + if (timeoutInterval == 0.0) { + timeoutInterval = 15.0; + } + + // In order to prevent from potential duplicate caching (NSURLCache + SDImageCache) we disable the cache for image requests if told otherwise + NSURLRequestCachePolicy cachePolicy = options & SDWebImageDownloaderUseNSURLCache ? NSURLRequestUseProtocolCachePolicy : NSURLRequestReloadIgnoringLocalCacheData; + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:cachePolicy + timeoutInterval:timeoutInterval]; + + request.HTTPShouldHandleCookies = (options & SDWebImageDownloaderHandleCookies); + request.HTTPShouldUsePipelining = YES; + if (self.headersFilter) { + request.allHTTPHeaderFields = self.headersFilter(url, [self allHTTPHeaderFields]); + } + else { + request.allHTTPHeaderFields = [self allHTTPHeaderFields]; + } + NSOperation *operation = [[self.operationClass alloc] initWithRequest:request inSession:self.session options:options]; + operation.shouldDecompressImages = self.shouldDecompressImages; + + if (self.urlCredential) { + operation.credential = self.urlCredential; + } else if (self.username && self.password) { + operation.credential = [NSURLCredential credentialWithUser:self.username password:self.password persistence:NSURLCredentialPersistenceForSession]; + } + + if (options & SDWebImageDownloaderHighPriority) { + operation.queuePriority = NSOperationQueuePriorityHigh; + } else if (options & SDWebImageDownloaderLowPriority) { + operation.queuePriority = NSOperationQueuePriorityLow; + } + + if (self.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) { + // Emulate LIFO execution order by systematically adding new operations as last operation's dependency + [self.lastAddedOperation addDependency:operation]; + self.lastAddedOperation = operation; + } + + return operation; +} + +- (void)cancel:(nullable SDWebImageDownloadToken *)token { + NSURL *url = token.url; + if (!url) { + return; + } + LOCK(self.operationsLock); + NSOperation *operation = [self.URLOperations objectForKey:url]; + if (operation) { + BOOL canceled = [operation cancel:token.downloadOperationCancelToken]; + if (canceled) { + [self.URLOperations removeObjectForKey:url]; + } + } + UNLOCK(self.operationsLock); +} + +- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(NSURL *)url + completed:(SDWebImageDownloaderCompletedBlock)completedBlock { + return [self downloadImageWithURL:url options:0 progress:nil completed:completedBlock]; +} + +- (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url + options:(SDWebImageDownloaderOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { + // The URL will be used as the key to the callbacks dictionary so it cannot be nil. If it is nil immediately call the completed block with no image or data. + if (url == nil) { + if (completedBlock != nil) { + completedBlock(nil, nil, nil, NO); + } + return nil; + } + + LOCK(self.operationsLock); + NSOperation *operation = [self.URLOperations objectForKey:url]; + // There is a case that the operation may be marked as finished or cancelled, but not been removed from `self.URLOperations`. + if (!operation || operation.isFinished || operation.isCancelled) { + operation = [self createDownloaderOperationWithUrl:url options:options]; + __weak typeof(self) wself = self; + operation.completionBlock = ^{ + __strong typeof(wself) sself = wself; + if (!sself) { + return; + } + LOCK(sself.operationsLock); + [sself.URLOperations removeObjectForKey:url]; + UNLOCK(sself.operationsLock); + }; + [self.URLOperations setObject:operation forKey:url]; + // Add operation to operation queue only after all configuration done according to Apple's doc. + // `addOperation:` does not synchronously execute the `operation.completionBlock` so this will not cause deadlock. + [self.downloadQueue addOperation:operation]; + } + else if (!operation.isExecuting) { + if (options & SDWebImageDownloaderHighPriority) { + operation.queuePriority = NSOperationQueuePriorityHigh; + } else if (options & SDWebImageDownloaderLowPriority) { + operation.queuePriority = NSOperationQueuePriorityLow; + } else { + operation.queuePriority = NSOperationQueuePriorityNormal; + } + } + UNLOCK(self.operationsLock); + + id downloadOperationCancelToken = [operation addHandlersForProgress:progressBlock completed:completedBlock]; + + SDWebImageDownloadToken *token = [SDWebImageDownloadToken new]; + token.downloadOperation = operation; + token.url = url; + token.downloadOperationCancelToken = downloadOperationCancelToken; + + return token; +} + +- (void)setSuspended:(BOOL)suspended { + self.downloadQueue.suspended = suspended; +} + +- (void)cancelAllDownloads { + [self.downloadQueue cancelAllOperations]; +} + +#pragma mark Helper methods + +- (NSOperation *)operationWithTask:(NSURLSessionTask *)task { + NSOperation *returnOperation = nil; + for (NSOperation *operation in self.downloadQueue.operations) { + if ([operation respondsToSelector:@selector(dataTask)]) { + if (operation.dataTask.taskIdentifier == task.taskIdentifier) { + returnOperation = operation; + break; + } + } + } + return returnOperation; +} + +#pragma mark NSURLSessionDataDelegate + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { + + // Identify the operation that runs this task and pass it the delegate method + NSOperation *dataOperation = [self operationWithTask:dataTask]; + if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:didReceiveResponse:completionHandler:)]) { + [dataOperation URLSession:session dataTask:dataTask didReceiveResponse:response completionHandler:completionHandler]; + } else { + if (completionHandler) { + completionHandler(NSURLSessionResponseAllow); + } + } +} + +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { + + // Identify the operation that runs this task and pass it the delegate method + NSOperation *dataOperation = [self operationWithTask:dataTask]; + if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:didReceiveData:)]) { + [dataOperation URLSession:session dataTask:dataTask didReceiveData:data]; + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler { + + // Identify the operation that runs this task and pass it the delegate method + NSOperation *dataOperation = [self operationWithTask:dataTask]; + if ([dataOperation respondsToSelector:@selector(URLSession:dataTask:willCacheResponse:completionHandler:)]) { + [dataOperation URLSession:session dataTask:dataTask willCacheResponse:proposedResponse completionHandler:completionHandler]; + } else { + if (completionHandler) { + completionHandler(proposedResponse); + } + } +} + +#pragma mark NSURLSessionTaskDelegate + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { + + // Identify the operation that runs this task and pass it the delegate method + NSOperation *dataOperation = [self operationWithTask:task]; + if ([dataOperation respondsToSelector:@selector(URLSession:task:didCompleteWithError:)]) { + [dataOperation URLSession:session task:task didCompleteWithError:error]; + } +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler { + + // Identify the operation that runs this task and pass it the delegate method + NSOperation *dataOperation = [self operationWithTask:task]; + if ([dataOperation respondsToSelector:@selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)]) { + [dataOperation URLSession:session task:task willPerformHTTPRedirection:response newRequest:request completionHandler:completionHandler]; + } else { + if (completionHandler) { + completionHandler(request); + } + } +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { + + // Identify the operation that runs this task and pass it the delegate method + NSOperation *dataOperation = [self operationWithTask:task]; + if ([dataOperation respondsToSelector:@selector(URLSession:task:didReceiveChallenge:completionHandler:)]) { + [dataOperation URLSession:session task:task didReceiveChallenge:challenge completionHandler:completionHandler]; + } else { + if (completionHandler) { + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + } + } +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.h b/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.h new file mode 100644 index 0000000..6d9d95c --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.h @@ -0,0 +1,128 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageDownloader.h" +#import "SDWebImageOperation.h" + +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStartNotification; +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadReceiveResponseNotification; +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadStopNotification; +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageDownloadFinishNotification; + + + +/** + Describes a downloader operation. If one wants to use a custom downloader op, it needs to inherit from `NSOperation` and conform to this protocol + For the description about these methods, see `SDWebImageDownloaderOperation` + */ +@protocol SDWebImageDownloaderOperationInterface +@required +- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request + inSession:(nullable NSURLSession *)session + options:(SDWebImageDownloaderOptions)options; + +- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; + +- (BOOL)shouldDecompressImages; +- (void)setShouldDecompressImages:(BOOL)value; + +- (nullable NSURLCredential *)credential; +- (void)setCredential:(nullable NSURLCredential *)value; + +- (BOOL)cancel:(nullable id)token; + +@optional +- (nullable NSURLSessionTask *)dataTask; + +@end + + +@interface SDWebImageDownloaderOperation : NSOperation + +/** + * The request used by the operation's task. + */ +@property (strong, nonatomic, readonly, nullable) NSURLRequest *request; + +/** + * The operation's task + */ +@property (strong, nonatomic, readonly, nullable) NSURLSessionTask *dataTask; + + +@property (assign, nonatomic) BOOL shouldDecompressImages; + +/** + * Was used to determine whether the URL connection should consult the credential storage for authenticating the connection. + * @deprecated Not used for a couple of versions + */ +@property (nonatomic, assign) BOOL shouldUseCredentialStorage __deprecated_msg("Property deprecated. Does nothing. Kept only for backwards compatibility"); + +/** + * The credential used for authentication challenges in `-URLSession:task:didReceiveChallenge:completionHandler:`. + * + * This will be overridden by any shared credentials that exist for the username or password of the request URL, if present. + */ +@property (nonatomic, strong, nullable) NSURLCredential *credential; + +/** + * The SDWebImageDownloaderOptions for the receiver. + */ +@property (assign, nonatomic, readonly) SDWebImageDownloaderOptions options; + +/** + * The expected size of data. + */ +@property (assign, nonatomic) NSInteger expectedSize; + +/** + * The response returned by the operation's task. + */ +@property (strong, nonatomic, nullable) NSURLResponse *response; + +/** + * Initializes a `SDWebImageDownloaderOperation` object + * + * @see SDWebImageDownloaderOperation + * + * @param request the URL request + * @param session the URL session in which this operation will run + * @param options downloader options + * + * @return the initialized instance + */ +- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request + inSession:(nullable NSURLSession *)session + options:(SDWebImageDownloaderOptions)options NS_DESIGNATED_INITIALIZER; + +/** + * Adds handlers for progress and completion. Returns a tokent that can be passed to -cancel: to cancel this set of + * callbacks. + * + * @param progressBlock the block executed when a new chunk of data arrives. + * @note the progress block is executed on a background queue + * @param completedBlock the block executed when the download is done. + * @note the completed block is executed on the main queue for success. If errors are found, there is a chance the block will be executed on a background queue + * + * @return the token to use to cancel this set of handlers + */ +- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock; + +/** + * Cancels a set of callbacks. Once all callbacks are canceled, the operation is cancelled. + * + * @param token the token representing a set of callbacks to cancel + * + * @return YES if the operation was stopped because this was the last token to be canceled. NO otherwise. + */ +- (BOOL)cancel:(nullable id)token; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m b/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m new file mode 100644 index 0000000..c10ba8d --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageDownloaderOperation.m @@ -0,0 +1,506 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageDownloaderOperation.h" +#import "SDWebImageManager.h" +#import "NSImage+WebCache.h" +#import "SDWebImageCodersManager.h" +#import "UIImage+MultiFormat.h" + +#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); +#define UNLOCK(lock) dispatch_semaphore_signal(lock); + +// iOS 8 Foundation.framework extern these symbol but the define is in CFNetwork.framework. We just fix this without import CFNetwork.framework +#if (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) +const float NSURLSessionTaskPriorityHigh = 0.75; +const float NSURLSessionTaskPriorityDefault = 0.5; +const float NSURLSessionTaskPriorityLow = 0.25; +#endif + +NSString *const SDWebImageDownloadStartNotification = @"SDWebImageDownloadStartNotification"; +NSString *const SDWebImageDownloadReceiveResponseNotification = @"SDWebImageDownloadReceiveResponseNotification"; +NSString *const SDWebImageDownloadStopNotification = @"SDWebImageDownloadStopNotification"; +NSString *const SDWebImageDownloadFinishNotification = @"SDWebImageDownloadFinishNotification"; + +static NSString *const kProgressCallbackKey = @"progress"; +static NSString *const kCompletedCallbackKey = @"completed"; + +typedef NSMutableDictionary SDCallbacksDictionary; + +@interface SDWebImageDownloaderOperation () + +@property (strong, nonatomic, nonnull) NSMutableArray *callbackBlocks; + +@property (assign, nonatomic, getter = isExecuting) BOOL executing; +@property (assign, nonatomic, getter = isFinished) BOOL finished; +@property (strong, nonatomic, nullable) NSMutableData *imageData; +@property (copy, nonatomic, nullable) NSData *cachedData; // for `SDWebImageDownloaderIgnoreCachedResponse` + +// This is weak because it is injected by whoever manages this session. If this gets nil-ed out, we won't be able to run +// the task associated with this operation +@property (weak, nonatomic, nullable) NSURLSession *unownedSession; +// This is set if we're using not using an injected NSURLSession. We're responsible of invalidating this one +@property (strong, nonatomic, nullable) NSURLSession *ownedSession; + +@property (strong, nonatomic, readwrite, nullable) NSURLSessionTask *dataTask; + +@property (strong, nonatomic, nonnull) dispatch_semaphore_t callbacksLock; // a lock to keep the access to `callbackBlocks` thread-safe + +@property (strong, nonatomic, nonnull) dispatch_queue_t coderQueue; // the queue to do image decoding +#if SD_UIKIT +@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundTaskId; +#endif + +@property (strong, nonatomic, nullable) id progressiveCoder; + +@end + +@implementation SDWebImageDownloaderOperation + +@synthesize executing = _executing; +@synthesize finished = _finished; + +- (nonnull instancetype)init { + return [self initWithRequest:nil inSession:nil options:0]; +} + +- (nonnull instancetype)initWithRequest:(nullable NSURLRequest *)request + inSession:(nullable NSURLSession *)session + options:(SDWebImageDownloaderOptions)options { + if ((self = [super init])) { + _request = [request copy]; + _shouldDecompressImages = YES; + _options = options; + _callbackBlocks = [NSMutableArray new]; + _executing = NO; + _finished = NO; + _expectedSize = 0; + _unownedSession = session; + _callbacksLock = dispatch_semaphore_create(1); + _coderQueue = dispatch_queue_create("com.hackemist.SDWebImageDownloaderOperationCoderQueue", DISPATCH_QUEUE_SERIAL); +#if SD_UIKIT + _backgroundTaskId = UIBackgroundTaskInvalid; +#endif + } + return self; +} + +- (nullable id)addHandlersForProgress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDWebImageDownloaderCompletedBlock)completedBlock { + SDCallbacksDictionary *callbacks = [NSMutableDictionary new]; + if (progressBlock) callbacks[kProgressCallbackKey] = [progressBlock copy]; + if (completedBlock) callbacks[kCompletedCallbackKey] = [completedBlock copy]; + LOCK(self.callbacksLock); + [self.callbackBlocks addObject:callbacks]; + UNLOCK(self.callbacksLock); + return callbacks; +} + +- (nullable NSArray *)callbacksForKey:(NSString *)key { + LOCK(self.callbacksLock); + NSMutableArray *callbacks = [[self.callbackBlocks valueForKey:key] mutableCopy]; + UNLOCK(self.callbacksLock); + // We need to remove [NSNull null] because there might not always be a progress block for each callback + [callbacks removeObjectIdenticalTo:[NSNull null]]; + return [callbacks copy]; // strip mutability here +} + +- (BOOL)cancel:(nullable id)token { + BOOL shouldCancel = NO; + LOCK(self.callbacksLock); + [self.callbackBlocks removeObjectIdenticalTo:token]; + if (self.callbackBlocks.count == 0) { + shouldCancel = YES; + } + UNLOCK(self.callbacksLock); + if (shouldCancel) { + [self cancel]; + } + return shouldCancel; +} + +- (void)start { + @synchronized (self) { + if (self.isCancelled) { + self.finished = YES; + [self reset]; + return; + } + +#if SD_UIKIT + Class UIApplicationClass = NSClassFromString(@"UIApplication"); + BOOL hasApplication = UIApplicationClass && [UIApplicationClass respondsToSelector:@selector(sharedApplication)]; + if (hasApplication && [self shouldContinueWhenAppEntersBackground]) { + __weak __typeof__ (self) wself = self; + UIApplication * app = [UIApplicationClass performSelector:@selector(sharedApplication)]; + self.backgroundTaskId = [app beginBackgroundTaskWithExpirationHandler:^{ + [wself cancel]; + }]; + } +#endif + NSURLSession *session = self.unownedSession; + if (!session) { + NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + sessionConfig.timeoutIntervalForRequest = 15; + + /** + * Create the session for this task + * We send nil as delegate queue so that the session creates a serial operation queue for performing all delegate + * method calls and completion handler calls. + */ + session = [NSURLSession sessionWithConfiguration:sessionConfig + delegate:self + delegateQueue:nil]; + self.ownedSession = session; + } + + if (self.options & SDWebImageDownloaderIgnoreCachedResponse) { + // Grab the cached data for later check + NSURLCache *URLCache = session.configuration.URLCache; + if (!URLCache) { + URLCache = [NSURLCache sharedURLCache]; + } + NSCachedURLResponse *cachedResponse; + // NSURLCache's `cachedResponseForRequest:` is not thread-safe, see https://developer.apple.com/documentation/foundation/nsurlcache#2317483 + @synchronized (URLCache) { + cachedResponse = [URLCache cachedResponseForRequest:self.request]; + } + if (cachedResponse) { + self.cachedData = cachedResponse.data; + } + } + + self.dataTask = [session dataTaskWithRequest:self.request]; + self.executing = YES; + } + + if (self.dataTask) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + if ([self.dataTask respondsToSelector:@selector(setPriority:)]) { + if (self.options & SDWebImageDownloaderHighPriority) { + self.dataTask.priority = NSURLSessionTaskPriorityHigh; + } else if (self.options & SDWebImageDownloaderLowPriority) { + self.dataTask.priority = NSURLSessionTaskPriorityLow; + } + } +#pragma clang diagnostic pop + [self.dataTask resume]; + for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { + progressBlock(0, NSURLResponseUnknownLength, self.request.URL); + } + __block typeof(self) strongSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:strongSelf]; + }); + } else { + [self callCompletionBlocksWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorUnknown userInfo:@{NSLocalizedDescriptionKey : @"Task can't be initialized"}]]; + [self done]; + } +} + +- (void)cancel { + @synchronized (self) { + [self cancelInternal]; + } +} + +- (void)cancelInternal { + if (self.isFinished) return; + [super cancel]; + + if (self.dataTask) { + [self.dataTask cancel]; + __block typeof(self) strongSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:strongSelf]; + }); + + // As we cancelled the task, its callback won't be called and thus won't + // maintain the isFinished and isExecuting flags. + if (self.isExecuting) self.executing = NO; + if (!self.isFinished) self.finished = YES; + } + + [self reset]; +} + +- (void)done { + self.finished = YES; + self.executing = NO; + [self reset]; +} + +- (void)reset { + LOCK(self.callbacksLock); + [self.callbackBlocks removeAllObjects]; + UNLOCK(self.callbacksLock); + + @synchronized (self) { + self.dataTask = nil; + + if (self.ownedSession) { + [self.ownedSession invalidateAndCancel]; + self.ownedSession = nil; + } + +#if SD_UIKIT + if (self.backgroundTaskId != UIBackgroundTaskInvalid) { + // If backgroundTaskId != UIBackgroundTaskInvalid, sharedApplication is always exist + UIApplication * app = [UIApplication performSelector:@selector(sharedApplication)]; + [app endBackgroundTask:self.backgroundTaskId]; + self.backgroundTaskId = UIBackgroundTaskInvalid; + } +#endif + } +} + +- (void)setFinished:(BOOL)finished { + [self willChangeValueForKey:@"isFinished"]; + _finished = finished; + [self didChangeValueForKey:@"isFinished"]; +} + +- (void)setExecuting:(BOOL)executing { + [self willChangeValueForKey:@"isExecuting"]; + _executing = executing; + [self didChangeValueForKey:@"isExecuting"]; +} + +- (BOOL)isConcurrent { + return YES; +} + +#pragma mark NSURLSessionDataDelegate + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask +didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { + NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow; + NSInteger expected = (NSInteger)response.expectedContentLength; + expected = expected > 0 ? expected : 0; + self.expectedSize = expected; + self.response = response; + NSInteger statusCode = [response respondsToSelector:@selector(statusCode)] ? ((NSHTTPURLResponse *)response).statusCode : 200; + BOOL valid = statusCode < 400; + //'304 Not Modified' is an exceptional one. It should be treated as cancelled if no cache data + //URLSession current behavior will return 200 status code when the server respond 304 and URLCache hit. But this is not a standard behavior and we just add a check + if (statusCode == 304 && !self.cachedData) { + valid = NO; + } + + if (valid) { + for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { + progressBlock(0, expected, self.request.URL); + } + } else { + // Status code invalid and marked as cancelled. Do not call `[self.dataTask cancel]` which may mass up URLSession life cycle + disposition = NSURLSessionResponseCancel; + } + __block typeof(self) strongSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadReceiveResponseNotification object:strongSelf]; + }); + + if (completionHandler) { + completionHandler(disposition); + } +} + +- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { + if (!self.imageData) { + self.imageData = [[NSMutableData alloc] initWithCapacity:self.expectedSize]; + } + [self.imageData appendData:data]; + + if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0) { + // Get the image data + __block NSData *imageData = [self.imageData copy]; + // Get the total bytes downloaded + const NSInteger totalSize = imageData.length; + // Get the finish status + BOOL finished = (totalSize >= self.expectedSize); + + if (!self.progressiveCoder) { + // We need to create a new instance for progressive decoding to avoid conflicts + for (idcoder in [SDWebImageCodersManager sharedInstance].coders) { + if ([coder conformsToProtocol:@protocol(SDWebImageProgressiveCoder)] && + [((id)coder) canIncrementallyDecodeFromData:imageData]) { + self.progressiveCoder = [[[coder class] alloc] init]; + break; + } + } + } + + // progressive decode the image in coder queue + dispatch_async(self.coderQueue, ^{ + @autoreleasepool { + UIImage *image = [self.progressiveCoder incrementallyDecodedImageWithData:imageData finished:finished]; + if (image) { + NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; + image = [self scaledImageForKey:key image:image]; + if (self.shouldDecompressImages) { + image = [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; + } + + // We do not keep the progressive decoding image even when `finished`=YES. Because they are for view rendering but not take full function from downloader options. And some coders implementation may not keep consistent between progressive decoding and normal decoding. + + [self callCompletionBlocksWithImage:image imageData:nil error:nil finished:NO]; + } + } + }); + } + + for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { + progressBlock(self.imageData.length, self.expectedSize, self.request.URL); + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + willCacheResponse:(NSCachedURLResponse *)proposedResponse + completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler { + + NSCachedURLResponse *cachedResponse = proposedResponse; + + if (!(self.options & SDWebImageDownloaderUseNSURLCache)) { + // Prevents caching of responses + cachedResponse = nil; + } + if (completionHandler) { + completionHandler(cachedResponse); + } +} + +#pragma mark NSURLSessionTaskDelegate + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { + @synchronized(self) { + self.dataTask = nil; + __block typeof(self) strongSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:strongSelf]; + if (!error) { + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadFinishNotification object:strongSelf]; + } + }); + } + + // make sure to call `[self done]` to mark operation as finished + if (error) { + [self callCompletionBlocksWithError:error]; + [self done]; + } else { + if ([self callbacksForKey:kCompletedCallbackKey].count > 0) { + /** + * If you specified to use `NSURLCache`, then the response you get here is what you need. + */ + __block NSData *imageData = [self.imageData copy]; + self.imageData = nil; + if (imageData) { + /** if you specified to only use cached data via `SDWebImageDownloaderIgnoreCachedResponse`, + * then we should check if the cached data is equal to image data + */ + if (self.options & SDWebImageDownloaderIgnoreCachedResponse && [self.cachedData isEqualToData:imageData]) { + // call completion block with nil + [self callCompletionBlocksWithImage:nil imageData:nil error:nil finished:YES]; + [self done]; + } else { + // decode the image in coder queue + dispatch_async(self.coderQueue, ^{ + @autoreleasepool { + UIImage *image = [[SDWebImageCodersManager sharedInstance] decodedImageWithData:imageData]; + NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:self.request.URL]; + image = [self scaledImageForKey:key image:image]; + + // Do not force decoding animated images or GIF, + // because there has imageCoder which can change `image` or `imageData` to static image, lose the animated feature totally. + BOOL shouldDecode = !image.images && image.sd_imageFormat != SDImageFormatGIF; + if (shouldDecode) { + if (self.shouldDecompressImages) { + BOOL shouldScaleDown = self.options & SDWebImageDownloaderScaleDownLargeImages; + image = [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&imageData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(shouldScaleDown)}]; + } + } + CGSize imageSize = image.size; + if (imageSize.width == 0 || imageSize.height == 0) { + [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0 pixels"}]]; + } else { + [self callCompletionBlocksWithImage:image imageData:imageData error:nil finished:YES]; + } + [self done]; + } + }); + } + } else { + [self callCompletionBlocksWithError:[NSError errorWithDomain:SDWebImageErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Image data is nil"}]]; + [self done]; + } + } else { + [self done]; + } + } +} + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { + + NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; + __block NSURLCredential *credential = nil; + + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + if (!(self.options & SDWebImageDownloaderAllowInvalidSSLCertificates)) { + disposition = NSURLSessionAuthChallengePerformDefaultHandling; + } else { + credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; + disposition = NSURLSessionAuthChallengeUseCredential; + } + } else { + if (challenge.previousFailureCount == 0) { + if (self.credential) { + credential = self.credential; + disposition = NSURLSessionAuthChallengeUseCredential; + } else { + disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; + } + } else { + disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; + } + } + + if (completionHandler) { + completionHandler(disposition, credential); + } +} + +#pragma mark Helper methods +- (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image { + return SDScaledImageForKey(key, image); +} + +- (BOOL)shouldContinueWhenAppEntersBackground { + return self.options & SDWebImageDownloaderContinueInBackground; +} + +- (void)callCompletionBlocksWithError:(nullable NSError *)error { + [self callCompletionBlocksWithImage:nil imageData:nil error:error finished:YES]; +} + +- (void)callCompletionBlocksWithImage:(nullable UIImage *)image + imageData:(nullable NSData *)imageData + error:(nullable NSError *)error + finished:(BOOL)finished { + NSArray *completionBlocks = [self callbacksForKey:kCompletedCallbackKey]; + dispatch_main_async_safe(^{ + for (SDWebImageDownloaderCompletedBlock completedBlock in completionBlocks) { + completedBlock(image, imageData, error, finished); + } + }); +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageFrame.h b/Pods/SDWebImage/SDWebImage/SDWebImageFrame.h new file mode 100644 index 0000000..c3a0f71 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageFrame.h @@ -0,0 +1,34 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCompat.h" + +@interface SDWebImageFrame : NSObject + +// This class is used for creating animated images via `animatedImageWithFrames` in `SDWebImageCoderHelper`. Attention if you need to specify animated images loop count, use `sd_imageLoopCount` property in `UIImage+MultiFormat`. + +/** + The image of current frame. You should not set an animated image. + */ +@property (nonatomic, strong, readonly, nonnull) UIImage *image; +/** + The duration of current frame to be displayed. The number is seconds but not milliseconds. You should not set this to zero. + */ +@property (nonatomic, readonly, assign) NSTimeInterval duration; + +/** + Create a frame instance with specify image and duration + + @param image current frame's image + @param duration current frame's duration + @return frame instance + */ ++ (instancetype _Nonnull)frameWithImage:(UIImage * _Nonnull)image duration:(NSTimeInterval)duration; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageFrame.m b/Pods/SDWebImage/SDWebImage/SDWebImageFrame.m new file mode 100644 index 0000000..b0aefe5 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageFrame.m @@ -0,0 +1,28 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageFrame.h" + +@interface SDWebImageFrame () + +@property (nonatomic, strong, readwrite, nonnull) UIImage *image; +@property (nonatomic, readwrite, assign) NSTimeInterval duration; + +@end + +@implementation SDWebImageFrame + ++ (instancetype)frameWithImage:(UIImage *)image duration:(NSTimeInterval)duration { + SDWebImageFrame *frame = [[SDWebImageFrame alloc] init]; + frame.image = image; + frame.duration = duration; + + return frame; +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageGIFCoder.h b/Pods/SDWebImage/SDWebImage/SDWebImageGIFCoder.h new file mode 100644 index 0000000..30521f9 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageGIFCoder.h @@ -0,0 +1,23 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCoder.h" + +/** + Built in coder using ImageIO that supports GIF encoding/decoding + @note `SDWebImageIOCoder` supports GIF but only as static (will use the 1st frame). + @note Use `SDWebImageGIFCoder` for fully animated GIFs - less performant than `FLAnimatedImage` + @note If you decide to make all `UIImageView`(including `FLAnimatedImageView`) instance support GIF. You should add this coder to `SDWebImageCodersManager` and make sure that it has a higher priority than `SDWebImageIOCoder` + @note The recommended approach for animated GIFs is using `FLAnimatedImage`. It's more performant than `UIImageView` for GIF displaying + */ +@interface SDWebImageGIFCoder : NSObject + ++ (nonnull instancetype)sharedCoder; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageGIFCoder.m b/Pods/SDWebImage/SDWebImage/SDWebImageGIFCoder.m new file mode 100644 index 0000000..e43b773 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageGIFCoder.m @@ -0,0 +1,184 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageGIFCoder.h" +#import "NSImage+WebCache.h" +#import +#import "NSData+ImageContentType.h" +#import "UIImage+MultiFormat.h" +#import "SDWebImageCoderHelper.h" +#import "SDAnimatedImageRep.h" + +@implementation SDWebImageGIFCoder + ++ (instancetype)sharedCoder { + static SDWebImageGIFCoder *coder; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + coder = [[SDWebImageGIFCoder alloc] init]; + }); + return coder; +} + +#pragma mark - Decode +- (BOOL)canDecodeFromData:(nullable NSData *)data { + return ([NSData sd_imageFormatForImageData:data] == SDImageFormatGIF); +} + +- (UIImage *)decodedImageWithData:(NSData *)data { + if (!data) { + return nil; + } + +#if SD_MAC + SDAnimatedImageRep *imageRep = [[SDAnimatedImageRep alloc] initWithData:data]; + NSImage *animatedImage = [[NSImage alloc] initWithSize:imageRep.size]; + [animatedImage addRepresentation:imageRep]; + return animatedImage; +#else + + CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); + if (!source) { + return nil; + } + size_t count = CGImageSourceGetCount(source); + + UIImage *animatedImage; + + if (count <= 1) { + animatedImage = [[UIImage alloc] initWithData:data]; + } else { + NSMutableArray *frames = [NSMutableArray array]; + + for (size_t i = 0; i < count; i++) { + CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, i, NULL); + if (!imageRef) { + continue; + } + + float duration = [self sd_frameDurationAtIndex:i source:source]; + UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; + CGImageRelease(imageRef); + + SDWebImageFrame *frame = [SDWebImageFrame frameWithImage:image duration:duration]; + [frames addObject:frame]; + } + + NSUInteger loopCount = 1; + NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(source, nil); + NSDictionary *gifProperties = [imageProperties valueForKey:(__bridge NSString *)kCGImagePropertyGIFDictionary]; + if (gifProperties) { + NSNumber *gifLoopCount = [gifProperties valueForKey:(__bridge NSString *)kCGImagePropertyGIFLoopCount]; + if (gifLoopCount != nil) { + loopCount = gifLoopCount.unsignedIntegerValue; + } + } + + animatedImage = [SDWebImageCoderHelper animatedImageWithFrames:frames]; + animatedImage.sd_imageLoopCount = loopCount; + animatedImage.sd_imageFormat = SDImageFormatGIF; + } + + CFRelease(source); + + return animatedImage; +#endif +} + +- (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { + float frameDuration = 0.1f; + CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil); + if (!cfFrameProperties) { + return frameDuration; + } + NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties; + NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary]; + + NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime]; + if (delayTimeUnclampedProp != nil) { + frameDuration = [delayTimeUnclampedProp floatValue]; + } else { + NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime]; + if (delayTimeProp != nil) { + frameDuration = [delayTimeProp floatValue]; + } + } + + // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. + // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify + // a duration of <= 10 ms. See and + // for more information. + + if (frameDuration < 0.011f) { + frameDuration = 0.100f; + } + + CFRelease(cfFrameProperties); + return frameDuration; +} + +- (UIImage *)decompressedImageWithImage:(UIImage *)image + data:(NSData *__autoreleasing _Nullable *)data + options:(nullable NSDictionary*)optionsDict { + // GIF do not decompress + return image; +} + +#pragma mark - Encode +- (BOOL)canEncodeToFormat:(SDImageFormat)format { + return (format == SDImageFormatGIF); +} + +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format { + if (!image) { + return nil; + } + + if (format != SDImageFormatGIF) { + return nil; + } + + NSMutableData *imageData = [NSMutableData data]; + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatGIF]; + NSArray *frames = [SDWebImageCoderHelper framesFromAnimatedImage:image]; + + // Create an image destination. GIF does not support EXIF image orientation + CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frames.count, NULL); + if (!imageDestination) { + // Handle failure. + return nil; + } + if (frames.count == 0) { + // for static single GIF images + CGImageDestinationAddImage(imageDestination, image.CGImage, nil); + } else { + // for animated GIF images + NSUInteger loopCount = image.sd_imageLoopCount; + NSDictionary *gifProperties = @{(__bridge NSString *)kCGImagePropertyGIFDictionary: @{(__bridge NSString *)kCGImagePropertyGIFLoopCount : @(loopCount)}}; + CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)gifProperties); + + for (size_t i = 0; i < frames.count; i++) { + SDWebImageFrame *frame = frames[i]; + float frameDuration = frame.duration; + CGImageRef frameImageRef = frame.image.CGImage; + NSDictionary *frameProperties = @{(__bridge NSString *)kCGImagePropertyGIFDictionary : @{(__bridge NSString *)kCGImagePropertyGIFDelayTime : @(frameDuration)}}; + CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties); + } + } + // Finalize the destination. + if (CGImageDestinationFinalize(imageDestination) == NO) { + // Handle failure. + imageData = nil; + } + + CFRelease(imageDestination); + + return [imageData copy]; +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.h b/Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.h new file mode 100644 index 0000000..04f68fb --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.h @@ -0,0 +1,30 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageCoder.h" + +/** + Built in coder that supports PNG, JPEG, TIFF, includes support for progressive decoding. + + GIF + Also supports static GIF (meaning will only handle the 1st frame). + For a full GIF support, we recommend `FLAnimatedImage` or our less performant `SDWebImageGIFCoder` + + HEIC + This coder also supports HEIC format because ImageIO supports it natively. But it depends on the system capabilities, so it won't work on all devices, see: https://devstreaming-cdn.apple.com/videos/wwdc/2017/511tj33587vdhds/511/511_working_with_heif_and_hevc.pdf + Decode(Software): !Simulator && (iOS 11 || tvOS 11 || macOS 10.13) + Decode(Hardware): !Simulator && ((iOS 11 && A9Chip) || (macOS 10.13 && 6thGenerationIntelCPU)) + Encode(Software): macOS 10.13 + Encode(Hardware): !Simulator && ((iOS 11 && A10FusionChip) || (macOS 10.13 && 6thGenerationIntelCPU)) + */ +@interface SDWebImageImageIOCoder : NSObject + ++ (nonnull instancetype)sharedCoder; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.m b/Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.m new file mode 100644 index 0000000..8f31e97 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageImageIOCoder.m @@ -0,0 +1,536 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageImageIOCoder.h" +#import "SDWebImageCoderHelper.h" +#import "NSImage+WebCache.h" +#import +#import "NSData+ImageContentType.h" +#import "UIImage+MultiFormat.h" + +#if SD_UIKIT || SD_WATCH +static const size_t kBytesPerPixel = 4; +static const size_t kBitsPerComponent = 8; + +/* + * Defines the maximum size in MB of the decoded image when the flag `SDWebImageScaleDownLargeImages` is set + * Suggested value for iPad1 and iPhone 3GS: 60. + * Suggested value for iPad2 and iPhone 4: 120. + * Suggested value for iPhone 3G and iPod 2 and earlier devices: 30. + */ +static const CGFloat kDestImageSizeMB = 60.0f; + +/* + * Defines the maximum size in MB of a tile used to decode image when the flag `SDWebImageScaleDownLargeImages` is set + * Suggested value for iPad1 and iPhone 3GS: 20. + * Suggested value for iPad2 and iPhone 4: 40. + * Suggested value for iPhone 3G and iPod 2 and earlier devices: 10. + */ +static const CGFloat kSourceImageTileSizeMB = 20.0f; + +static const CGFloat kBytesPerMB = 1024.0f * 1024.0f; +static const CGFloat kPixelsPerMB = kBytesPerMB / kBytesPerPixel; +static const CGFloat kDestTotalPixels = kDestImageSizeMB * kPixelsPerMB; +static const CGFloat kTileTotalPixels = kSourceImageTileSizeMB * kPixelsPerMB; + +static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to overlap the seems where tiles meet. +#endif + +@implementation SDWebImageImageIOCoder { + size_t _width, _height; +#if SD_UIKIT || SD_WATCH + UIImageOrientation _orientation; +#endif + CGImageSourceRef _imageSource; +} + +- (void)dealloc { + if (_imageSource) { + CFRelease(_imageSource); + _imageSource = NULL; + } +} + ++ (instancetype)sharedCoder { + static SDWebImageImageIOCoder *coder; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + coder = [[SDWebImageImageIOCoder alloc] init]; + }); + return coder; +} + +#pragma mark - Decode +- (BOOL)canDecodeFromData:(nullable NSData *)data { + switch ([NSData sd_imageFormatForImageData:data]) { + case SDImageFormatWebP: + // Do not support WebP decoding + return NO; + case SDImageFormatHEIC: + // Check HEIC decoding compatibility + return [[self class] canDecodeFromHEICFormat]; + case SDImageFormatHEIF: + // Check HEIF decoding compatibility + return [[self class] canDecodeFromHEIFFormat]; + default: + return YES; + } +} + +- (BOOL)canIncrementallyDecodeFromData:(NSData *)data { + switch ([NSData sd_imageFormatForImageData:data]) { + case SDImageFormatWebP: + // Do not support WebP progressive decoding + return NO; + case SDImageFormatHEIC: + // Check HEIC decoding compatibility + return [[self class] canDecodeFromHEICFormat]; + case SDImageFormatHEIF: + // Check HEIF decoding compatibility + return [[self class] canDecodeFromHEIFFormat]; + default: + return YES; + } +} + +- (UIImage *)decodedImageWithData:(NSData *)data { + if (!data) { + return nil; + } + + UIImage *image = [[UIImage alloc] initWithData:data]; + image.sd_imageFormat = [NSData sd_imageFormatForImageData:data]; + + return image; +} + +- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished { + if (!_imageSource) { + _imageSource = CGImageSourceCreateIncremental(NULL); + } + UIImage *image; + + // The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/ + // Thanks to the author @Nyx0uf + + // Update the data source, we must pass ALL the data, not just the new bytes + CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)data, finished); + + if (_width + _height == 0) { + CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL); + if (properties) { + NSInteger orientationValue = 1; + CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight); + if (val) CFNumberGetValue(val, kCFNumberLongType, &_height); + val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); + if (val) CFNumberGetValue(val, kCFNumberLongType, &_width); + val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); + if (val) CFNumberGetValue(val, kCFNumberNSIntegerType, &orientationValue); + CFRelease(properties); + + // When we draw to Core Graphics, we lose orientation information, + // which means the image below born of initWithCGIImage will be + // oriented incorrectly sometimes. (Unlike the image born of initWithData + // in didCompleteWithError.) So save it here and pass it on later. +#if SD_UIKIT || SD_WATCH + _orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:orientationValue]; +#endif + } + } + + if (_width + _height > 0) { + // Create the image + CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL); + + if (partialImageRef) { +#if SD_UIKIT || SD_WATCH + image = [[UIImage alloc] initWithCGImage:partialImageRef scale:1 orientation:_orientation]; +#elif SD_MAC + image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize]; +#endif + CGImageRelease(partialImageRef); + image.sd_imageFormat = [NSData sd_imageFormatForImageData:data]; + } + } + + if (finished) { + if (_imageSource) { + CFRelease(_imageSource); + _imageSource = NULL; + } + } + + return image; +} + +- (UIImage *)decompressedImageWithImage:(UIImage *)image + data:(NSData *__autoreleasing _Nullable *)data + options:(nullable NSDictionary*)optionsDict { +#if SD_MAC + return image; +#endif +#if SD_UIKIT || SD_WATCH + BOOL shouldScaleDown = NO; + if (optionsDict != nil) { + NSNumber *scaleDownLargeImagesOption = nil; + if ([optionsDict[SDWebImageCoderScaleDownLargeImagesKey] isKindOfClass:[NSNumber class]]) { + scaleDownLargeImagesOption = (NSNumber *)optionsDict[SDWebImageCoderScaleDownLargeImagesKey]; + } + if (scaleDownLargeImagesOption != nil) { + shouldScaleDown = [scaleDownLargeImagesOption boolValue]; + } + } + if (!shouldScaleDown) { + return [self sd_decompressedImageWithImage:image]; + } else { + UIImage *scaledDownImage = [self sd_decompressedAndScaledDownImageWithImage:image]; + if (scaledDownImage && !CGSizeEqualToSize(scaledDownImage.size, image.size)) { + // if the image is scaled down, need to modify the data pointer as well + SDImageFormat format = [NSData sd_imageFormatForImageData:*data]; + NSData *imageData = [self encodedDataWithImage:scaledDownImage format:format]; + if (imageData) { + *data = imageData; + } + } + return scaledDownImage; + } +#endif +} + +#if SD_UIKIT || SD_WATCH +- (nullable UIImage *)sd_decompressedImageWithImage:(nullable UIImage *)image { + if (![[self class] shouldDecodeImage:image]) { + return image; + } + + // autorelease the bitmap context and all vars to help system to free memory when there are memory warning. + // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory]; + @autoreleasepool{ + + CGImageRef imageRef = image.CGImage; + // device color space + CGColorSpaceRef colorspaceRef = SDCGColorSpaceGetDeviceRGB(); + BOOL hasAlpha = SDCGImageRefContainsAlpha(imageRef); + // iOS display alpha info (BRGA8888/BGRX8888) + CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; + bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; + + size_t width = CGImageGetWidth(imageRef); + size_t height = CGImageGetHeight(imageRef); + + // kCGImageAlphaNone is not supported in CGBitmapContextCreate. + // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast + // to create bitmap graphics contexts without alpha info. + CGContextRef context = CGBitmapContextCreate(NULL, + width, + height, + kBitsPerComponent, + 0, + colorspaceRef, + bitmapInfo); + if (context == NULL) { + return image; + } + + // Draw the image into the context and retrieve the new bitmap image without alpha + CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); + CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context); + UIImage *imageWithoutAlpha = [[UIImage alloc] initWithCGImage:imageRefWithoutAlpha scale:image.scale orientation:image.imageOrientation]; + CGContextRelease(context); + CGImageRelease(imageRefWithoutAlpha); + + return imageWithoutAlpha; + } +} + +- (nullable UIImage *)sd_decompressedAndScaledDownImageWithImage:(nullable UIImage *)image { + if (![[self class] shouldDecodeImage:image]) { + return image; + } + + if (![[self class] shouldScaleDownImage:image]) { + return [self sd_decompressedImageWithImage:image]; + } + + CGContextRef destContext; + + // autorelease the bitmap context and all vars to help system to free memory when there are memory warning. + // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory]; + @autoreleasepool { + CGImageRef sourceImageRef = image.CGImage; + + CGSize sourceResolution = CGSizeZero; + sourceResolution.width = CGImageGetWidth(sourceImageRef); + sourceResolution.height = CGImageGetHeight(sourceImageRef); + CGFloat sourceTotalPixels = sourceResolution.width * sourceResolution.height; + // Determine the scale ratio to apply to the input image + // that results in an output image of the defined size. + // see kDestImageSizeMB, and how it relates to destTotalPixels. + CGFloat imageScale = sqrt(kDestTotalPixels / sourceTotalPixels); + CGSize destResolution = CGSizeZero; + destResolution.width = (int)(sourceResolution.width * imageScale); + destResolution.height = (int)(sourceResolution.height * imageScale); + + // device color space + CGColorSpaceRef colorspaceRef = SDCGColorSpaceGetDeviceRGB(); + BOOL hasAlpha = SDCGImageRefContainsAlpha(sourceImageRef); + // iOS display alpha info (BGRA8888/BGRX8888) + CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; + bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; + + // kCGImageAlphaNone is not supported in CGBitmapContextCreate. + // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast + // to create bitmap graphics contexts without alpha info. + destContext = CGBitmapContextCreate(NULL, + destResolution.width, + destResolution.height, + kBitsPerComponent, + 0, + colorspaceRef, + bitmapInfo); + + if (destContext == NULL) { + return image; + } + CGContextSetInterpolationQuality(destContext, kCGInterpolationHigh); + + // Now define the size of the rectangle to be used for the + // incremental blits from the input image to the output image. + // we use a source tile width equal to the width of the source + // image due to the way that iOS retrieves image data from disk. + // iOS must decode an image from disk in full width 'bands', even + // if current graphics context is clipped to a subrect within that + // band. Therefore we fully utilize all of the pixel data that results + // from a decoding opertion by achnoring our tile size to the full + // width of the input image. + CGRect sourceTile = CGRectZero; + sourceTile.size.width = sourceResolution.width; + // The source tile height is dynamic. Since we specified the size + // of the source tile in MB, see how many rows of pixels high it + // can be given the input image width. + sourceTile.size.height = (int)(kTileTotalPixels / sourceTile.size.width ); + sourceTile.origin.x = 0.0f; + // The output tile is the same proportions as the input tile, but + // scaled to image scale. + CGRect destTile; + destTile.size.width = destResolution.width; + destTile.size.height = sourceTile.size.height * imageScale; + destTile.origin.x = 0.0f; + // The source seem overlap is proportionate to the destination seem overlap. + // this is the amount of pixels to overlap each tile as we assemble the ouput image. + float sourceSeemOverlap = (int)((kDestSeemOverlap/destResolution.height)*sourceResolution.height); + CGImageRef sourceTileImageRef; + // calculate the number of read/write operations required to assemble the + // output image. + int iterations = (int)( sourceResolution.height / sourceTile.size.height ); + // If tile height doesn't divide the image height evenly, add another iteration + // to account for the remaining pixels. + int remainder = (int)sourceResolution.height % (int)sourceTile.size.height; + if(remainder) { + iterations++; + } + // Add seem overlaps to the tiles, but save the original tile height for y coordinate calculations. + float sourceTileHeightMinusOverlap = sourceTile.size.height; + sourceTile.size.height += sourceSeemOverlap; + destTile.size.height += kDestSeemOverlap; + for( int y = 0; y < iterations; ++y ) { + @autoreleasepool { + sourceTile.origin.y = y * sourceTileHeightMinusOverlap + sourceSeemOverlap; + destTile.origin.y = destResolution.height - (( y + 1 ) * sourceTileHeightMinusOverlap * imageScale + kDestSeemOverlap); + sourceTileImageRef = CGImageCreateWithImageInRect( sourceImageRef, sourceTile ); + if( y == iterations - 1 && remainder ) { + float dify = destTile.size.height; + destTile.size.height = CGImageGetHeight( sourceTileImageRef ) * imageScale; + dify -= destTile.size.height; + destTile.origin.y += dify; + } + CGContextDrawImage( destContext, destTile, sourceTileImageRef ); + CGImageRelease( sourceTileImageRef ); + } + } + + CGImageRef destImageRef = CGBitmapContextCreateImage(destContext); + CGContextRelease(destContext); + if (destImageRef == NULL) { + return image; + } + UIImage *destImage = [[UIImage alloc] initWithCGImage:destImageRef scale:image.scale orientation:image.imageOrientation]; + CGImageRelease(destImageRef); + if (destImage == nil) { + return image; + } + return destImage; + } +} +#endif + +#pragma mark - Encode +- (BOOL)canEncodeToFormat:(SDImageFormat)format { + switch (format) { + case SDImageFormatWebP: + // Do not support WebP encoding + return NO; + case SDImageFormatHEIC: + // Check HEIC encoding compatibility + return [[self class] canEncodeToHEICFormat]; + case SDImageFormatHEIF: + // Check HEIF encoding compatibility + return [[self class] canEncodeToHEIFFormat]; + default: + return YES; + } +} + +- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format { + if (!image) { + return nil; + } + + if (format == SDImageFormatUndefined) { + BOOL hasAlpha = SDCGImageRefContainsAlpha(image.CGImage); + if (hasAlpha) { + format = SDImageFormatPNG; + } else { + format = SDImageFormatJPEG; + } + } + + NSMutableData *imageData = [NSMutableData data]; + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:format]; + + // Create an image destination. + CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL); + if (!imageDestination) { + // Handle failure. + return nil; + } + + NSMutableDictionary *properties = [NSMutableDictionary dictionary]; +#if SD_UIKIT || SD_WATCH + NSInteger exifOrientation = [SDWebImageCoderHelper exifOrientationFromImageOrientation:image.imageOrientation]; + [properties setValue:@(exifOrientation) forKey:(__bridge NSString *)kCGImagePropertyOrientation]; +#endif + + // Add your image to the destination. + CGImageDestinationAddImage(imageDestination, image.CGImage, (__bridge CFDictionaryRef)properties); + + // Finalize the destination. + if (CGImageDestinationFinalize(imageDestination) == NO) { + // Handle failure. + imageData = nil; + } + + CFRelease(imageDestination); + + return [imageData copy]; +} + +#pragma mark - Helper ++ (BOOL)shouldDecodeImage:(nullable UIImage *)image { + // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error + if (image == nil) { + return NO; + } + + // do not decode animated images + if (image.images != nil) { + return NO; + } + + return YES; +} + ++ (BOOL)canDecodeFromHEICFormat { + static BOOL canDecode = NO; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatHEIC]; + NSArray *imageUTTypes = (__bridge_transfer NSArray *)CGImageSourceCopyTypeIdentifiers(); + if ([imageUTTypes containsObject:(__bridge NSString *)(imageUTType)]) { + canDecode = YES; + } + }); + return canDecode; +} + ++ (BOOL)canDecodeFromHEIFFormat { + static BOOL canDecode = NO; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatHEIF]; + NSArray *imageUTTypes = (__bridge_transfer NSArray *)CGImageSourceCopyTypeIdentifiers(); + if ([imageUTTypes containsObject:(__bridge NSString *)(imageUTType)]) { + canDecode = YES; + } + }); + return canDecode; +} + ++ (BOOL)canEncodeToHEICFormat { + static BOOL canEncode = NO; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSMutableData *imageData = [NSMutableData data]; + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatHEIC]; + + // Create an image destination. + CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL); + if (!imageDestination) { + // Can't encode to HEIC + canEncode = NO; + } else { + // Can encode to HEIC + CFRelease(imageDestination); + canEncode = YES; + } + }); + return canEncode; +} + ++ (BOOL)canEncodeToHEIFFormat { + static BOOL canEncode = NO; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSMutableData *imageData = [NSMutableData data]; + CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:SDImageFormatHEIF]; + + // Create an image destination. + CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, 1, NULL); + if (!imageDestination) { + // Can't encode to HEIF + canEncode = NO; + } else { + // Can encode to HEIF + CFRelease(imageDestination); + canEncode = YES; + } + }); + return canEncode; +} + +#if SD_UIKIT || SD_WATCH ++ (BOOL)shouldScaleDownImage:(nonnull UIImage *)image { + BOOL shouldScaleDown = YES; + + CGImageRef sourceImageRef = image.CGImage; + CGSize sourceResolution = CGSizeZero; + sourceResolution.width = CGImageGetWidth(sourceImageRef); + sourceResolution.height = CGImageGetHeight(sourceImageRef); + float sourceTotalPixels = sourceResolution.width * sourceResolution.height; + float imageScale = kDestTotalPixels / sourceTotalPixels; + if (imageScale < 1) { + shouldScaleDown = YES; + } else { + shouldScaleDown = NO; + } + + return shouldScaleDown; +} +#endif + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageManager.h b/Pods/SDWebImage/SDWebImage/SDWebImageManager.h new file mode 100644 index 0000000..9168021 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageManager.h @@ -0,0 +1,328 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "SDWebImageOperation.h" +#import "SDWebImageDownloader.h" +#import "SDImageCache.h" + +typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { + /** + * By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying. + * This flag disable this blacklisting. + */ + SDWebImageRetryFailed = 1 << 0, + + /** + * By default, image downloads are started during UI interactions, this flags disable this feature, + * leading to delayed download on UIScrollView deceleration for instance. + */ + SDWebImageLowPriority = 1 << 1, + + /** + * This flag disables on-disk caching after the download finished, only cache in memory + */ + SDWebImageCacheMemoryOnly = 1 << 2, + + /** + * This flag enables progressive download, the image is displayed progressively during download as a browser would do. + * By default, the image is only displayed once completely downloaded. + */ + SDWebImageProgressiveDownload = 1 << 3, + + /** + * Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed. + * The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation. + * This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics. + * If a cached image is refreshed, the completion block is called once with the cached image and again with the final image. + * + * Use this flag only if you can't make your URLs static with embedded cache busting parameter. + */ + SDWebImageRefreshCached = 1 << 4, + + /** + * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for + * extra time in background to let the request finish. If the background task expires the operation will be cancelled. + */ + SDWebImageContinueInBackground = 1 << 5, + + /** + * Handles cookies stored in NSHTTPCookieStore by setting + * NSMutableURLRequest.HTTPShouldHandleCookies = YES; + */ + SDWebImageHandleCookies = 1 << 6, + + /** + * Enable to allow untrusted SSL certificates. + * Useful for testing purposes. Use with caution in production. + */ + SDWebImageAllowInvalidSSLCertificates = 1 << 7, + + /** + * By default, images are loaded in the order in which they were queued. This flag moves them to + * the front of the queue. + */ + SDWebImageHighPriority = 1 << 8, + + /** + * By default, placeholder images are loaded while the image is loading. This flag will delay the loading + * of the placeholder image until after the image has finished loading. + */ + SDWebImageDelayPlaceholder = 1 << 9, + + /** + * We usually don't call transformDownloadedImage delegate method on animated images, + * as most transformation code would mangle it. + * Use this flag to transform them anyway. + */ + SDWebImageTransformAnimatedImage = 1 << 10, + + /** + * By default, image is added to the imageView after download. But in some cases, we want to + * have the hand before setting the image (apply a filter or add it with cross-fade animation for instance) + * Use this flag if you want to manually set the image in the completion when success + */ + SDWebImageAvoidAutoSetImage = 1 << 11, + + /** + * By default, images are decoded respecting their original size. On iOS, this flag will scale down the + * images to a size compatible with the constrained memory of devices. + * If `SDWebImageProgressiveDownload` flag is set the scale down is deactivated. + */ + SDWebImageScaleDownLargeImages = 1 << 12, + + /** + * By default, we do not query disk data when the image is cached in memory. This mask can force to query disk data at the same time. + * This flag is recommend to be used with `SDWebImageQueryDiskSync` to ensure the image is loaded in the same runloop. + */ + SDWebImageQueryDataWhenInMemory = 1 << 13, + + /** + * By default, we query the memory cache synchronously, disk cache asynchronously. This mask can force to query disk cache synchronously to ensure that image is loaded in the same runloop. + * This flag can avoid flashing during cell reuse if you disable memory cache or in some other cases. + */ + SDWebImageQueryDiskSync = 1 << 14, + + /** + * By default, when the cache missed, the image is download from the network. This flag can prevent network to load from cache only. + */ + SDWebImageFromCacheOnly = 1 << 15, + /** + * By default, when you use `SDWebImageTransition` to do some view transition after the image load finished, this transition is only applied for image download from the network. This mask can force to apply view transition for memory and disk cache as well. + */ + SDWebImageForceTransition = 1 << 16 +}; + +typedef void(^SDExternalCompletionBlock)(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL); + +typedef void(^SDInternalCompletionBlock)(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL); + +typedef NSString * _Nullable(^SDWebImageCacheKeyFilterBlock)(NSURL * _Nullable url); + +typedef NSData * _Nullable(^SDWebImageCacheSerializerBlock)(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL); + + +@class SDWebImageManager; + +@protocol SDWebImageManagerDelegate + +@optional + +/** + * Controls which image should be downloaded when the image is not found in the cache. + * + * @param imageManager The current `SDWebImageManager` + * @param imageURL The url of the image to be downloaded + * + * @return Return NO to prevent the downloading of the image on cache misses. If not implemented, YES is implied. + */ +- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldDownloadImageForURL:(nullable NSURL *)imageURL; + +/** + * Controls the complicated logic to mark as failed URLs when download error occur. + * If the delegate implement this method, we will not use the built-in way to mark URL as failed based on error code; + @param imageManager The current `SDWebImageManager` + @param imageURL The url of the image + @param error The download error for the url + @return Whether to block this url or not. Return YES to mark this URL as failed. + */ +- (BOOL)imageManager:(nonnull SDWebImageManager *)imageManager shouldBlockFailedURL:(nonnull NSURL *)imageURL withError:(nonnull NSError *)error; + +/** + * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory. + * NOTE: This method is called from a global queue in order to not to block the main thread. + * + * @param imageManager The current `SDWebImageManager` + * @param image The image to transform + * @param imageURL The url of the image to transform + * + * @return The transformed image object. + */ +- (nullable UIImage *)imageManager:(nonnull SDWebImageManager *)imageManager transformDownloadedImage:(nullable UIImage *)image withURL:(nullable NSURL *)imageURL; + +@end + +/** + * The SDWebImageManager is the class behind the UIImageView+WebCache category and likes. + * It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache). + * You can use this class directly to benefit from web image downloading with caching in another context than + * a UIView. + * + * Here is a simple example of how to use SDWebImageManager: + * + * @code + +SDWebImageManager *manager = [SDWebImageManager sharedManager]; +[manager loadImageWithURL:imageURL + options:0 + progress:nil + completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (image) { + // do something with image + } + }]; + + * @endcode + */ +@interface SDWebImageManager : NSObject + +@property (weak, nonatomic, nullable) id delegate; + +@property (strong, nonatomic, readonly, nullable) SDImageCache *imageCache; +@property (strong, nonatomic, readonly, nullable) SDWebImageDownloader *imageDownloader; + +/** + * The cache filter is a block used each time SDWebImageManager need to convert an URL into a cache key. This can + * be used to remove dynamic part of an image URL. + * + * The following example sets a filter in the application delegate that will remove any query-string from the + * URL before to use it as a cache key: + * + * @code + +SDWebImageManager.sharedManager.cacheKeyFilter = ^(NSURL * _Nullable url) { + url = [[NSURL alloc] initWithScheme:url.scheme host:url.host path:url.path]; + return [url absoluteString]; +}; + + * @endcode + */ +@property (nonatomic, copy, nullable) SDWebImageCacheKeyFilterBlock cacheKeyFilter; + +/** + * The cache serializer is a block used to convert the decoded image, the source downloaded data, to the actual data used for storing to the disk cache. If you return nil, means to generate the data from the image instance, see `SDImageCache`. + * For example, if you are using WebP images and facing the slow decoding time issue when later retriving from disk cache again. You can try to encode the decoded image to JPEG/PNG format to disk cache instead of source downloaded data. + * @note The `image` arg is nonnull, but when you also provide a image transformer and the image is transformed, the `data` arg may be nil, take attention to this case. + * @note This method is called from a global queue in order to not to block the main thread. + * @code + SDWebImageManager.sharedManager.cacheSerializer = ^NSData * _Nullable(UIImage * _Nonnull image, NSData * _Nullable data, NSURL * _Nullable imageURL) { + SDImageFormat format = [NSData sd_imageFormatForImageData:data]; + switch (format) { + case SDImageFormatWebP: + return image.images ? data : nil; + default: + return data; + } + }; + * @endcode + * The default value is nil. Means we just store the source downloaded data to disk cache. + */ +@property (nonatomic, copy, nullable) SDWebImageCacheSerializerBlock cacheSerializer; + +/** + * Returns global SDWebImageManager instance. + * + * @return SDWebImageManager shared instance + */ ++ (nonnull instancetype)sharedManager; + +/** + * Allows to specify instance of cache and image downloader used with image manager. + * @return new instance of `SDWebImageManager` with specified cache and downloader. + */ +- (nonnull instancetype)initWithCache:(nonnull SDImageCache *)cache downloader:(nonnull SDWebImageDownloader *)downloader NS_DESIGNATED_INITIALIZER; + +/** + * Downloads the image at the given URL if not present in cache or return the cached version otherwise. + * + * @param url The URL to the image + * @param options A mask to specify options to use for this request + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. + * + * This parameter is required. + * + * This block has no return value and takes the requested UIImage as first parameter and the NSData representation as second parameter. + * In case of error the image parameter is nil and the third parameter may contain an NSError. + * + * The forth parameter is an `SDImageCacheType` enum indicating if the image was retrieved from the local cache + * or from the memory cache or from the network. + * + * The fith parameter is set to NO when the SDWebImageProgressiveDownload option is used and the image is + * downloading. This block is thus called repeatedly with a partial image. When image is fully downloaded, the + * block is called a last time with the full image and the last parameter set to YES. + * + * The last parameter is the original image URL + * + * @return Returns an NSObject conforming to SDWebImageOperation. Should be an instance of SDWebImageDownloaderOperation + */ +- (nullable id )loadImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDInternalCompletionBlock)completedBlock; + +/** + * Saves image to cache for given URL + * + * @param image The image to cache + * @param url The URL to the image + * + */ + +- (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url; + +/** + * Cancel all current operations + */ +- (void)cancelAll; + +/** + * Check one or more operations running + */ +- (BOOL)isRunning; + +/** + * Async check if image has already been cached + * + * @param url image url + * @param completionBlock the block to be executed when the check is finished + * + * @note the completion block is always executed on the main queue + */ +- (void)cachedImageExistsForURL:(nullable NSURL *)url + completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock; + +/** + * Async check if image has already been cached on disk only + * + * @param url image url + * @param completionBlock the block to be executed when the check is finished + * + * @note the completion block is always executed on the main queue + */ +- (void)diskImageExistsForURL:(nullable NSURL *)url + completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock; + + +/** + *Return the cache key for a given URL + */ +- (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageManager.m b/Pods/SDWebImage/SDWebImage/SDWebImageManager.m new file mode 100644 index 0000000..c912fb5 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageManager.m @@ -0,0 +1,370 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageManager.h" +#import "NSImage+WebCache.h" +#import + +#define LOCK(lock) dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); +#define UNLOCK(lock) dispatch_semaphore_signal(lock); + +@interface SDWebImageCombinedOperation : NSObject + +@property (assign, nonatomic, getter = isCancelled) BOOL cancelled; +@property (strong, nonatomic, nullable) SDWebImageDownloadToken *downloadToken; +@property (strong, nonatomic, nullable) NSOperation *cacheOperation; +@property (weak, nonatomic, nullable) SDWebImageManager *manager; + +@end + +@interface SDWebImageManager () + +@property (strong, nonatomic, readwrite, nonnull) SDImageCache *imageCache; +@property (strong, nonatomic, readwrite, nonnull) SDWebImageDownloader *imageDownloader; +@property (strong, nonatomic, nonnull) NSMutableSet *failedURLs; +@property (strong, nonatomic, nonnull) dispatch_semaphore_t failedURLsLock; // a lock to keep the access to `failedURLs` thread-safe +@property (strong, nonatomic, nonnull) NSMutableSet *runningOperations; +@property (strong, nonatomic, nonnull) dispatch_semaphore_t runningOperationsLock; // a lock to keep the access to `runningOperations` thread-safe + +@end + +@implementation SDWebImageManager + ++ (nonnull instancetype)sharedManager { + static dispatch_once_t once; + static id instance; + dispatch_once(&once, ^{ + instance = [self new]; + }); + return instance; +} + +- (nonnull instancetype)init { + SDImageCache *cache = [SDImageCache sharedImageCache]; + SDWebImageDownloader *downloader = [SDWebImageDownloader sharedDownloader]; + return [self initWithCache:cache downloader:downloader]; +} + +- (nonnull instancetype)initWithCache:(nonnull SDImageCache *)cache downloader:(nonnull SDWebImageDownloader *)downloader { + if ((self = [super init])) { + _imageCache = cache; + _imageDownloader = downloader; + _failedURLs = [NSMutableSet new]; + _failedURLsLock = dispatch_semaphore_create(1); + _runningOperations = [NSMutableSet new]; + _runningOperationsLock = dispatch_semaphore_create(1); + } + return self; +} + +- (nullable NSString *)cacheKeyForURL:(nullable NSURL *)url { + if (!url) { + return @""; + } + + if (self.cacheKeyFilter) { + return self.cacheKeyFilter(url); + } else { + return url.absoluteString; + } +} + +- (nullable UIImage *)scaledImageForKey:(nullable NSString *)key image:(nullable UIImage *)image { + return SDScaledImageForKey(key, image); +} + +- (void)cachedImageExistsForURL:(nullable NSURL *)url + completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock { + NSString *key = [self cacheKeyForURL:url]; + + BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil); + + if (isInMemoryCache) { + // making sure we call the completion block on the main queue + dispatch_async(dispatch_get_main_queue(), ^{ + if (completionBlock) { + completionBlock(YES); + } + }); + return; + } + + [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) { + // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch + if (completionBlock) { + completionBlock(isInDiskCache); + } + }]; +} + +- (void)diskImageExistsForURL:(nullable NSURL *)url + completion:(nullable SDWebImageCheckCacheCompletionBlock)completionBlock { + NSString *key = [self cacheKeyForURL:url]; + + [self.imageCache diskImageExistsWithKey:key completion:^(BOOL isInDiskCache) { + // the completion block of checkDiskCacheForImageWithKey:completion: is always called on the main queue, no need to further dispatch + if (completionBlock) { + completionBlock(isInDiskCache); + } + }]; +} + +- (id )loadImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDInternalCompletionBlock)completedBlock { + // Invoking this method without a completedBlock is pointless + NSAssert(completedBlock != nil, @"If you mean to prefetch the image, use -[SDWebImagePrefetcher prefetchURLs] instead"); + + // Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, Xcode won't + // throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString. + if ([url isKindOfClass:NSString.class]) { + url = [NSURL URLWithString:(NSString *)url]; + } + + // Prevents app crashing on argument type error like sending NSNull instead of NSURL + if (![url isKindOfClass:NSURL.class]) { + url = nil; + } + + SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new]; + operation.manager = self; + + BOOL isFailedUrl = NO; + if (url) { + LOCK(self.failedURLsLock); + isFailedUrl = [self.failedURLs containsObject:url]; + UNLOCK(self.failedURLsLock); + } + + if (url.absoluteString.length == 0 || (!(options & SDWebImageRetryFailed) && isFailedUrl)) { + [self callCompletionBlockForOperation:operation completion:completedBlock error:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil] url:url]; + return operation; + } + + LOCK(self.runningOperationsLock); + [self.runningOperations addObject:operation]; + UNLOCK(self.runningOperationsLock); + NSString *key = [self cacheKeyForURL:url]; + + SDImageCacheOptions cacheOptions = 0; + if (options & SDWebImageQueryDataWhenInMemory) cacheOptions |= SDImageCacheQueryDataWhenInMemory; + if (options & SDWebImageQueryDiskSync) cacheOptions |= SDImageCacheQueryDiskSync; + if (options & SDWebImageScaleDownLargeImages) cacheOptions |= SDImageCacheScaleDownLargeImages; + + __weak SDWebImageCombinedOperation *weakOperation = operation; + operation.cacheOperation = [self.imageCache queryCacheOperationForKey:key options:cacheOptions done:^(UIImage *cachedImage, NSData *cachedData, SDImageCacheType cacheType) { + __strong __typeof(weakOperation) strongOperation = weakOperation; + if (!strongOperation || strongOperation.isCancelled) { + [self safelyRemoveOperationFromRunning:strongOperation]; + return; + } + + // Check whether we should download image from network + BOOL shouldDownload = (!(options & SDWebImageFromCacheOnly)) + && (!cachedImage || options & SDWebImageRefreshCached) + && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]); + if (shouldDownload) { + if (cachedImage && options & SDWebImageRefreshCached) { + // If image was found in the cache but SDWebImageRefreshCached is provided, notify about the cached image + // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server. + [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; + } + + // download if no image or requested to refresh anyway, and download allowed by delegate + SDWebImageDownloaderOptions downloaderOptions = 0; + if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority; + if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload; + if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache; + if (options & SDWebImageContinueInBackground) downloaderOptions |= SDWebImageDownloaderContinueInBackground; + if (options & SDWebImageHandleCookies) downloaderOptions |= SDWebImageDownloaderHandleCookies; + if (options & SDWebImageAllowInvalidSSLCertificates) downloaderOptions |= SDWebImageDownloaderAllowInvalidSSLCertificates; + if (options & SDWebImageHighPriority) downloaderOptions |= SDWebImageDownloaderHighPriority; + if (options & SDWebImageScaleDownLargeImages) downloaderOptions |= SDWebImageDownloaderScaleDownLargeImages; + + if (cachedImage && options & SDWebImageRefreshCached) { + // force progressive off if image already cached but forced refreshing + downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload; + // ignore image read from NSURLCache if image if cached but force refreshing + downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse; + } + + // `SDWebImageCombinedOperation` -> `SDWebImageDownloadToken` -> `downloadOperationCancelToken`, which is a `SDCallbacksDictionary` and retain the completed block below, so we need weak-strong again to avoid retain cycle + __weak typeof(strongOperation) weakSubOperation = strongOperation; + strongOperation.downloadToken = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *downloadedData, NSError *error, BOOL finished) { + __strong typeof(weakSubOperation) strongSubOperation = weakSubOperation; + if (!strongSubOperation || strongSubOperation.isCancelled) { + // Do nothing if the operation was cancelled + // See #699 for more details + // if we would call the completedBlock, there could be a race condition between this block and another completedBlock for the same object, so if this one is called second, we will overwrite the new data + } else if (error) { + [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock error:error url:url]; + BOOL shouldBlockFailedURL; + // Check whether we should block failed url + if ([self.delegate respondsToSelector:@selector(imageManager:shouldBlockFailedURL:withError:)]) { + shouldBlockFailedURL = [self.delegate imageManager:self shouldBlockFailedURL:url withError:error]; + } else { + shouldBlockFailedURL = ( error.code != NSURLErrorNotConnectedToInternet + && error.code != NSURLErrorCancelled + && error.code != NSURLErrorTimedOut + && error.code != NSURLErrorInternationalRoamingOff + && error.code != NSURLErrorDataNotAllowed + && error.code != NSURLErrorCannotFindHost + && error.code != NSURLErrorCannotConnectToHost + && error.code != NSURLErrorNetworkConnectionLost); + } + + if (shouldBlockFailedURL) { + LOCK(self.failedURLsLock); + [self.failedURLs addObject:url]; + UNLOCK(self.failedURLsLock); + } + } + else { + if ((options & SDWebImageRetryFailed)) { + LOCK(self.failedURLsLock); + [self.failedURLs removeObject:url]; + UNLOCK(self.failedURLsLock); + } + + BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly); + + // We've done the scale process in SDWebImageDownloader with the shared manager, this is used for custom manager and avoid extra scale. + if (self != [SDWebImageManager sharedManager] && self.cacheKeyFilter && downloadedImage) { + downloadedImage = [self scaledImageForKey:key image:downloadedImage]; + } + + if (options & SDWebImageRefreshCached && cachedImage && !downloadedImage) { + // Image refresh hit the NSURLCache cache, do not call the completion block + } else if (downloadedImage && (!downloadedImage.images || (options & SDWebImageTransformAnimatedImage)) && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:)]) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + @autoreleasepool { + UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url]; + + if (transformedImage && finished) { + BOOL imageWasTransformed = ![transformedImage isEqual:downloadedImage]; + NSData *cacheData; + // pass nil if the image was transformed, so we can recalculate the data from the image + if (self.cacheSerializer) { + cacheData = self.cacheSerializer(transformedImage, (imageWasTransformed ? nil : downloadedData), url); + } else { + cacheData = (imageWasTransformed ? nil : downloadedData); + } + [self.imageCache storeImage:transformedImage imageData:cacheData forKey:key toDisk:cacheOnDisk completion:nil]; + } + + [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:transformedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; + } + }); + } else { + if (downloadedImage && finished) { + if (self.cacheSerializer) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + @autoreleasepool { + NSData *cacheData = self.cacheSerializer(downloadedImage, downloadedData, url); + [self.imageCache storeImage:downloadedImage imageData:cacheData forKey:key toDisk:cacheOnDisk completion:nil]; + } + }); + } else { + [self.imageCache storeImage:downloadedImage imageData:downloadedData forKey:key toDisk:cacheOnDisk completion:nil]; + } + } + [self callCompletionBlockForOperation:strongSubOperation completion:completedBlock image:downloadedImage data:downloadedData error:nil cacheType:SDImageCacheTypeNone finished:finished url:url]; + } + } + + if (finished) { + [self safelyRemoveOperationFromRunning:strongSubOperation]; + } + }]; + } else if (cachedImage) { + [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:cachedImage data:cachedData error:nil cacheType:cacheType finished:YES url:url]; + [self safelyRemoveOperationFromRunning:strongOperation]; + } else { + // Image not in cache and download disallowed by delegate + [self callCompletionBlockForOperation:strongOperation completion:completedBlock image:nil data:nil error:nil cacheType:SDImageCacheTypeNone finished:YES url:url]; + [self safelyRemoveOperationFromRunning:strongOperation]; + } + }]; + + return operation; +} + +- (void)saveImageToCache:(nullable UIImage *)image forURL:(nullable NSURL *)url { + if (image && url) { + NSString *key = [self cacheKeyForURL:url]; + [self.imageCache storeImage:image forKey:key toDisk:YES completion:nil]; + } +} + +- (void)cancelAll { + LOCK(self.runningOperationsLock); + NSSet *copiedOperations = [self.runningOperations copy]; + UNLOCK(self.runningOperationsLock); + [copiedOperations makeObjectsPerformSelector:@selector(cancel)]; // This will call `safelyRemoveOperationFromRunning:` and remove from the array +} + +- (BOOL)isRunning { + BOOL isRunning = NO; + LOCK(self.runningOperationsLock); + isRunning = (self.runningOperations.count > 0); + UNLOCK(self.runningOperationsLock); + return isRunning; +} + +- (void)safelyRemoveOperationFromRunning:(nullable SDWebImageCombinedOperation*)operation { + if (!operation) { + return; + } + LOCK(self.runningOperationsLock); + [self.runningOperations removeObject:operation]; + UNLOCK(self.runningOperationsLock); +} + +- (void)callCompletionBlockForOperation:(nullable SDWebImageCombinedOperation*)operation + completion:(nullable SDInternalCompletionBlock)completionBlock + error:(nullable NSError *)error + url:(nullable NSURL *)url { + [self callCompletionBlockForOperation:operation completion:completionBlock image:nil data:nil error:error cacheType:SDImageCacheTypeNone finished:YES url:url]; +} + +- (void)callCompletionBlockForOperation:(nullable SDWebImageCombinedOperation*)operation + completion:(nullable SDInternalCompletionBlock)completionBlock + image:(nullable UIImage *)image + data:(nullable NSData *)data + error:(nullable NSError *)error + cacheType:(SDImageCacheType)cacheType + finished:(BOOL)finished + url:(nullable NSURL *)url { + dispatch_main_async_safe(^{ + if (operation && !operation.isCancelled && completionBlock) { + completionBlock(image, data, error, cacheType, finished, url); + } + }); +} + +@end + + +@implementation SDWebImageCombinedOperation + +- (void)cancel { + @synchronized(self) { + self.cancelled = YES; + if (self.cacheOperation) { + [self.cacheOperation cancel]; + self.cacheOperation = nil; + } + if (self.downloadToken) { + [self.manager.imageDownloader cancel:self.downloadToken]; + } + [self.manager safelyRemoveOperationFromRunning:self]; + } +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageOperation.h b/Pods/SDWebImage/SDWebImage/SDWebImageOperation.h new file mode 100644 index 0000000..71094ee --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageOperation.h @@ -0,0 +1,15 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import + +@protocol SDWebImageOperation + +- (void)cancel; + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.h b/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.h new file mode 100644 index 0000000..93357f4 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.h @@ -0,0 +1,112 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import +#import "SDWebImageManager.h" + +@class SDWebImagePrefetcher; + +@protocol SDWebImagePrefetcherDelegate + +@optional + +/** + * Called when an image was prefetched. + * + * @param imagePrefetcher The current image prefetcher + * @param imageURL The image url that was prefetched + * @param finishedCount The total number of images that were prefetched (successful or not) + * @param totalCount The total number of images that were to be prefetched + */ +- (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(nullable NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount; + +/** + * Called when all images are prefetched. + * @param imagePrefetcher The current image prefetcher + * @param totalCount The total number of images that were prefetched (whether successful or not) + * @param skippedCount The total number of images that were skipped + */ +- (void)imagePrefetcher:(nonnull SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount; + +@end + +typedef void(^SDWebImagePrefetcherProgressBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls); +typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls); + +/** + * Prefetch some URLs in the cache for future use. Images are downloaded in low priority. + */ +@interface SDWebImagePrefetcher : NSObject + +/** + * The web image manager + */ +@property (strong, nonatomic, readonly, nonnull) SDWebImageManager *manager; + +/** + * Maximum number of URLs to prefetch at the same time. Defaults to 3. + */ +@property (nonatomic, assign) NSUInteger maxConcurrentDownloads; + +/** + * SDWebImageOptions for prefetcher. Defaults to SDWebImageLowPriority. + */ +@property (nonatomic, assign) SDWebImageOptions options; + +/** + * Queue options for Prefetcher. Defaults to Main Queue. + */ +@property (strong, nonatomic, nonnull) dispatch_queue_t prefetcherQueue; + +@property (weak, nonatomic, nullable) id delegate; + +/** + * Return the global image prefetcher instance. + */ ++ (nonnull instancetype)sharedImagePrefetcher; + +/** + * Allows you to instantiate a prefetcher with any arbitrary image manager. + */ +- (nonnull instancetype)initWithImageManager:(nonnull SDWebImageManager *)manager NS_DESIGNATED_INITIALIZER; + +/** + * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, + * currently one image is downloaded at a time, + * and skips images for failed downloads and proceed to the next image in the list. + * Any previously-running prefetch operations are canceled. + * + * @param urls list of URLs to prefetch + */ +- (void)prefetchURLs:(nullable NSArray *)urls; + +/** + * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, + * currently one image is downloaded at a time, + * and skips images for failed downloads and proceed to the next image in the list. + * Any previously-running prefetch operations are canceled. + * + * @param urls list of URLs to prefetch + * @param progressBlock block to be called when progress updates; + * first parameter is the number of completed (successful or not) requests, + * second parameter is the total number of images originally requested to be prefetched + * @param completionBlock block to be called when prefetching is completed + * first param is the number of completed (successful or not) requests, + * second parameter is the number of skipped requests + */ +- (void)prefetchURLs:(nullable NSArray *)urls + progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock + completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock; + +/** + * Remove and cancel queued list + */ +- (void)cancelPrefetching; + + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.m b/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.m new file mode 100644 index 0000000..18c433e --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImagePrefetcher.m @@ -0,0 +1,144 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImagePrefetcher.h" + +@interface SDWebImagePrefetcher () + +@property (strong, nonatomic, nonnull) SDWebImageManager *manager; +@property (strong, atomic, nullable) NSArray *prefetchURLs; // may be accessed from different queue +@property (assign, nonatomic) NSUInteger requestedCount; +@property (assign, nonatomic) NSUInteger skippedCount; +@property (assign, nonatomic) NSUInteger finishedCount; +@property (assign, nonatomic) NSTimeInterval startedTime; +@property (copy, nonatomic, nullable) SDWebImagePrefetcherCompletionBlock completionBlock; +@property (copy, nonatomic, nullable) SDWebImagePrefetcherProgressBlock progressBlock; + +@end + +@implementation SDWebImagePrefetcher + ++ (nonnull instancetype)sharedImagePrefetcher { + static dispatch_once_t once; + static id instance; + dispatch_once(&once, ^{ + instance = [self new]; + }); + return instance; +} + +- (nonnull instancetype)init { + return [self initWithImageManager:[SDWebImageManager new]]; +} + +- (nonnull instancetype)initWithImageManager:(SDWebImageManager *)manager { + if ((self = [super init])) { + _manager = manager; + _options = SDWebImageLowPriority; + _prefetcherQueue = dispatch_get_main_queue(); + self.maxConcurrentDownloads = 3; + } + return self; +} + +- (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads { + self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads; +} + +- (NSUInteger)maxConcurrentDownloads { + return self.manager.imageDownloader.maxConcurrentDownloads; +} + +- (void)startPrefetchingAtIndex:(NSUInteger)index { + NSURL *currentURL; + @synchronized(self) { + if (index >= self.prefetchURLs.count) return; + currentURL = self.prefetchURLs[index]; + self.requestedCount++; + } + [self.manager loadImageWithURL:currentURL options:self.options progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + if (!finished) return; + self.finishedCount++; + + if (self.progressBlock) { + self.progressBlock(self.finishedCount,(self.prefetchURLs).count); + } + if (!image) { + // Add last failed + self.skippedCount++; + } + if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) { + [self.delegate imagePrefetcher:self + didPrefetchURL:currentURL + finishedCount:self.finishedCount + totalCount:self.prefetchURLs.count + ]; + } + if (self.prefetchURLs.count > self.requestedCount) { + dispatch_async(self.prefetcherQueue, ^{ + // we need dispatch to avoid function recursion call. This can prevent stack overflow even for huge urls list + [self startPrefetchingAtIndex:self.requestedCount]; + }); + } else if (self.finishedCount == self.requestedCount) { + [self reportStatus]; + if (self.completionBlock) { + self.completionBlock(self.finishedCount, self.skippedCount); + self.completionBlock = nil; + } + self.progressBlock = nil; + } + }]; +} + +- (void)reportStatus { + NSUInteger total = (self.prefetchURLs).count; + if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) { + [self.delegate imagePrefetcher:self + didFinishWithTotalCount:(total - self.skippedCount) + skippedCount:self.skippedCount + ]; + } +} + +- (void)prefetchURLs:(nullable NSArray *)urls { + [self prefetchURLs:urls progress:nil completed:nil]; +} + +- (void)prefetchURLs:(nullable NSArray *)urls + progress:(nullable SDWebImagePrefetcherProgressBlock)progressBlock + completed:(nullable SDWebImagePrefetcherCompletionBlock)completionBlock { + [self cancelPrefetching]; // Prevent duplicate prefetch request + self.startedTime = CFAbsoluteTimeGetCurrent(); + self.prefetchURLs = urls; + self.completionBlock = completionBlock; + self.progressBlock = progressBlock; + + if (urls.count == 0) { + if (completionBlock) { + completionBlock(0,0); + } + } else { + // Starts prefetching from the very first image on the list with the max allowed concurrency + NSUInteger listCount = self.prefetchURLs.count; + for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) { + [self startPrefetchingAtIndex:i]; + } + } +} + +- (void)cancelPrefetching { + @synchronized(self) { + self.prefetchURLs = nil; + self.skippedCount = 0; + self.requestedCount = 0; + self.finishedCount = 0; + } + [self.manager cancelAll]; +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageTransition.h b/Pods/SDWebImage/SDWebImage/SDWebImageTransition.h new file mode 100644 index 0000000..6740108 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageTransition.h @@ -0,0 +1,98 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +#if SD_UIKIT || SD_MAC +#import "SDImageCache.h" + +// This class is used to provide a transition animation after the view category load image finished. Use this on `sd_imageTransition` in UIView+WebCache.h +// for UIKit(iOS & tvOS), we use `+[UIView transitionWithView:duration:options:animations:completion]` for transition animation. +// for AppKit(macOS), we use `+[NSAnimationContext runAnimationGroup:completionHandler:]` for transition animation. You can call `+[NSAnimationContext currentContext]` to grab the context during animations block. +// These transition are provided for basic usage. If you need complicated animation, consider to directly use Core Animation or use `SDWebImageAvoidAutoSetImage` and implement your own after image load finished. + +#if SD_UIKIT +typedef UIViewAnimationOptions SDWebImageAnimationOptions; +#else +typedef NS_OPTIONS(NSUInteger, SDWebImageAnimationOptions) { + SDWebImageAnimationOptionAllowsImplicitAnimation = 1 << 0, // specify `allowsImplicitAnimation` for the `NSAnimationContext` +}; +#endif + +typedef void (^SDWebImageTransitionPreparesBlock)(__kindof UIView * _Nonnull view, UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL); +typedef void (^SDWebImageTransitionAnimationsBlock)(__kindof UIView * _Nonnull view, UIImage * _Nullable image); +typedef void (^SDWebImageTransitionCompletionBlock)(BOOL finished); + +@interface SDWebImageTransition : NSObject + +/** + By default, we set the image to the view at the beginning of the animtions. You can disable this and provide custom set image process + */ +@property (nonatomic, assign) BOOL avoidAutoSetImage; +/** + The duration of the transition animation, measured in seconds. Defaults to 0.5. + */ +@property (nonatomic, assign) NSTimeInterval duration; +/** + The timing function used for all animations within this transition animation (macOS). + */ +@property (nonatomic, strong, nullable) CAMediaTimingFunction *timingFunction NS_AVAILABLE_MAC(10_7); +/** + A mask of options indicating how you want to perform the animations. + */ +@property (nonatomic, assign) SDWebImageAnimationOptions animationOptions; +/** + A block object to be executed before the animation sequence starts. + */ +@property (nonatomic, copy, nullable) SDWebImageTransitionPreparesBlock prepares; +/** + A block object that contains the changes you want to make to the specified view. + */ +@property (nonatomic, copy, nullable) SDWebImageTransitionAnimationsBlock animations; +/** + A block object to be executed when the animation sequence ends. + */ +@property (nonatomic, copy, nullable) SDWebImageTransitionCompletionBlock completion; + +@end + +// Convenience way to create transition. Remember to specify the duration if needed. +// for UIKit, these transition just use the correspond `animationOptions`. By default we enable `UIViewAnimationOptionAllowUserInteraction` to allow user interaction during transition. +// for AppKit, these transition use Core Animation in `animations`. So your view must be layer-backed. Set `wantsLayer = YES` before you apply it. + +@interface SDWebImageTransition (Conveniences) + +// class property is available in Xcode 8. We will drop the Xcode 7.3 support in 5.x +#if __has_feature(objc_class_property) +/// Fade transition. +@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *fadeTransition; +/// Flip from left transition. +@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromLeftTransition; +/// Flip from right transition. +@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromRightTransition; +/// Flip from top transition. +@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromTopTransition; +/// Flip from bottom transition. +@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *flipFromBottomTransition; +/// Curl up transition. +@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *curlUpTransition; +/// Curl down transition. +@property (nonatomic, class, nonnull, readonly) SDWebImageTransition *curlDownTransition; +#else ++ (nonnull instancetype)fadeTransition; ++ (nonnull instancetype)flipFromLeftTransition; ++ (nonnull instancetype)flipFromRightTransition; ++ (nonnull instancetype)flipFromTopTransition; ++ (nonnull instancetype)flipFromBottomTransition; ++ (nonnull instancetype)curlUpTransition; ++ (nonnull instancetype)curlDownTransition; +#endif + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/SDWebImageTransition.m b/Pods/SDWebImage/SDWebImage/SDWebImageTransition.m new file mode 100644 index 0000000..b04a4c3 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/SDWebImageTransition.m @@ -0,0 +1,137 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageTransition.h" + +#if SD_UIKIT || SD_MAC + +#if SD_MAC +#import +#endif + +@implementation SDWebImageTransition + +- (instancetype)init { + self = [super init]; + if (self) { + self.duration = 0.5; + } + return self; +} + +@end + +@implementation SDWebImageTransition (Conveniences) + ++ (SDWebImageTransition *)fadeTransition { + SDWebImageTransition *transition = [SDWebImageTransition new]; +#if SD_UIKIT + transition.animationOptions = UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowUserInteraction; +#else + transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) { + CATransition *trans = [CATransition animation]; + trans.type = kCATransitionFade; + [view.layer addAnimation:trans forKey:kCATransition]; + }; +#endif + return transition; +} + ++ (SDWebImageTransition *)flipFromLeftTransition { + SDWebImageTransition *transition = [SDWebImageTransition new]; +#if SD_UIKIT + transition.animationOptions = UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionAllowUserInteraction; +#else + transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) { + CATransition *trans = [CATransition animation]; + trans.type = kCATransitionPush; + trans.subtype = kCATransitionFromLeft; + [view.layer addAnimation:trans forKey:kCATransition]; + }; +#endif + return transition; +} + ++ (SDWebImageTransition *)flipFromRightTransition { + SDWebImageTransition *transition = [SDWebImageTransition new]; +#if SD_UIKIT + transition.animationOptions = UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationOptionAllowUserInteraction; +#else + transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) { + CATransition *trans = [CATransition animation]; + trans.type = kCATransitionPush; + trans.subtype = kCATransitionFromRight; + [view.layer addAnimation:trans forKey:kCATransition]; + }; +#endif + return transition; +} + ++ (SDWebImageTransition *)flipFromTopTransition { + SDWebImageTransition *transition = [SDWebImageTransition new]; +#if SD_UIKIT + transition.animationOptions = UIViewAnimationOptionTransitionFlipFromTop | UIViewAnimationOptionAllowUserInteraction; +#else + transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) { + CATransition *trans = [CATransition animation]; + trans.type = kCATransitionPush; + trans.subtype = kCATransitionFromTop; + [view.layer addAnimation:trans forKey:kCATransition]; + }; +#endif + return transition; +} + ++ (SDWebImageTransition *)flipFromBottomTransition { + SDWebImageTransition *transition = [SDWebImageTransition new]; +#if SD_UIKIT + transition.animationOptions = UIViewAnimationOptionTransitionFlipFromBottom | UIViewAnimationOptionAllowUserInteraction; +#else + transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) { + CATransition *trans = [CATransition animation]; + trans.type = kCATransitionPush; + trans.subtype = kCATransitionFromBottom; + [view.layer addAnimation:trans forKey:kCATransition]; + }; +#endif + return transition; +} + ++ (SDWebImageTransition *)curlUpTransition { + SDWebImageTransition *transition = [SDWebImageTransition new]; +#if SD_UIKIT + transition.animationOptions = UIViewAnimationOptionTransitionCurlUp | UIViewAnimationOptionAllowUserInteraction; +#else + transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) { + CATransition *trans = [CATransition animation]; + trans.type = kCATransitionReveal; + trans.subtype = kCATransitionFromTop; + [view.layer addAnimation:trans forKey:kCATransition]; + }; +#endif + return transition; +} + ++ (SDWebImageTransition *)curlDownTransition { + SDWebImageTransition *transition = [SDWebImageTransition new]; +#if SD_UIKIT + transition.animationOptions = UIViewAnimationOptionTransitionCurlDown | UIViewAnimationOptionAllowUserInteraction; +#else + transition.animations = ^(__kindof NSView * _Nonnull view, NSImage * _Nullable image) { + CATransition *trans = [CATransition animation]; + trans.type = kCATransitionReveal; + trans.subtype = kCATransitionFromBottom; + [view.layer addAnimation:trans forKey:kCATransition]; + }; +#endif + return transition; +} + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/UIButton+WebCache.h b/Pods/SDWebImage/SDWebImage/UIButton+WebCache.h new file mode 100644 index 0000000..61fada6 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIButton+WebCache.h @@ -0,0 +1,255 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +#if SD_UIKIT + +#import "SDWebImageManager.h" + +/** + * Integrates SDWebImage async downloading and caching of remote images with UIButtonView. + */ +@interface UIButton (WebCache) + +#pragma mark - Image + +/** + * Get the current image URL. + */ +- (nullable NSURL *)sd_currentImageURL; + +/** + * Get the image URL for a control state. + * + * @param state Which state you want to know the URL for. The values are described in UIControlState. + */ +- (nullable NSURL *)sd_imageURLForState:(UIControlState)state; + +/** + * Set the imageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url` and a placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @see sd_setImageWithURL:placeholderImage:options: + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + completed:(nullable SDExternalCompletionBlock)completedBlock; + +#pragma mark - Background Image + +/** + * Get the current background image URL. + */ +- (nullable NSURL *)sd_currentBackgroundImageURL; + +/** + * Get the background image URL for a control state. + * + * @param state Which state you want to know the URL for. The values are described in UIControlState. + */ +- (nullable NSURL *)sd_backgroundImageURLForState:(UIControlState)state; + +/** + * Set the backgroundImageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + */ +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state NS_REFINED_FOR_SWIFT; + +/** + * Set the backgroundImageView `image` with an `url` and a placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @see sd_setImageWithURL:placeholderImage:options: + */ +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; + +/** + * Set the backgroundImageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; + +/** + * Set the backgroundImageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the backgroundImageView `image` with an `url`, placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param state The state that uses the specified title. The values are described in UIControlState. + * @param placeholder The image to be set initially, until the image request finishes. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; + +/** + * Set the backgroundImageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + completed:(nullable SDExternalCompletionBlock)completedBlock; + +#pragma mark - Cancel + +/** + * Cancel the current image download + */ +- (void)sd_cancelImageLoadForState:(UIControlState)state; + +/** + * Cancel the current backgroundImage download + */ +- (void)sd_cancelBackgroundImageLoadForState:(UIControlState)state; + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/UIButton+WebCache.m b/Pods/SDWebImage/SDWebImage/UIButton+WebCache.m new file mode 100644 index 0000000..8cdadb6 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIButton+WebCache.m @@ -0,0 +1,181 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIButton+WebCache.h" + +#if SD_UIKIT + +#import "objc/runtime.h" +#import "UIView+WebCacheOperation.h" +#import "UIView+WebCache.h" + +static char imageURLStorageKey; + +typedef NSMutableDictionary SDStateImageURLDictionary; + +static inline NSString * imageURLKeyForState(UIControlState state) { + return [NSString stringWithFormat:@"image_%lu", (unsigned long)state]; +} + +static inline NSString * backgroundImageURLKeyForState(UIControlState state) { + return [NSString stringWithFormat:@"backgroundImage_%lu", (unsigned long)state]; +} + +static inline NSString * imageOperationKeyForState(UIControlState state) { + return [NSString stringWithFormat:@"UIButtonImageOperation%lu", (unsigned long)state]; +} + +static inline NSString * backgroundImageOperationKeyForState(UIControlState state) { + return [NSString stringWithFormat:@"UIButtonBackgroundImageOperation%lu", (unsigned long)state]; +} + +@implementation UIButton (WebCache) + +#pragma mark - Image + +- (nullable NSURL *)sd_currentImageURL { + NSURL *url = self.sd_imageURLStorage[imageURLKeyForState(self.state)]; + + if (!url) { + url = self.sd_imageURLStorage[imageURLKeyForState(UIControlStateNormal)]; + } + + return url; +} + +- (nullable NSURL *)sd_imageURLForState:(UIControlState)state { + return self.sd_imageURLStorage[imageURLKeyForState(state)]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state { + [self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + completed:(nullable SDExternalCompletionBlock)completedBlock { + if (!url) { + [self.sd_imageURLStorage removeObjectForKey:imageURLKeyForState(state)]; + } else { + self.sd_imageURLStorage[imageURLKeyForState(state)] = url; + } + + __weak typeof(self)weakSelf = self; + [self sd_internalSetImageWithURL:url + placeholderImage:placeholder + options:options + operationKey:imageOperationKeyForState(state) + setImageBlock:^(UIImage *image, NSData *imageData) { + [weakSelf setImage:image forState:state]; + } + progress:nil + completed:completedBlock]; +} + +#pragma mark - Background Image + +- (nullable NSURL *)sd_currentBackgroundImageURL { + NSURL *url = self.sd_imageURLStorage[backgroundImageURLKeyForState(self.state)]; + + if (!url) { + url = self.sd_imageURLStorage[backgroundImageURLKeyForState(UIControlStateNormal)]; + } + + return url; +} + +- (nullable NSURL *)sd_backgroundImageURLForState:(UIControlState)state { + return self.sd_imageURLStorage[backgroundImageURLKeyForState(state)]; +} + +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:nil]; +} + +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:nil]; +} + +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:options completed:nil]; +} + +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:nil options:0 completed:completedBlock]; +} + +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url forState:(UIControlState)state placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setBackgroundImageWithURL:url forState:state placeholderImage:placeholder options:0 completed:completedBlock]; +} + +- (void)sd_setBackgroundImageWithURL:(nullable NSURL *)url + forState:(UIControlState)state + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + completed:(nullable SDExternalCompletionBlock)completedBlock { + if (!url) { + [self.sd_imageURLStorage removeObjectForKey:backgroundImageURLKeyForState(state)]; + } else { + self.sd_imageURLStorage[backgroundImageURLKeyForState(state)] = url; + } + + __weak typeof(self)weakSelf = self; + [self sd_internalSetImageWithURL:url + placeholderImage:placeholder + options:options + operationKey:backgroundImageOperationKeyForState(state) + setImageBlock:^(UIImage *image, NSData *imageData) { + [weakSelf setBackgroundImage:image forState:state]; + } + progress:nil + completed:completedBlock]; +} + +#pragma mark - Cancel + +- (void)sd_cancelImageLoadForState:(UIControlState)state { + [self sd_cancelImageLoadOperationWithKey:imageOperationKeyForState(state)]; +} + +- (void)sd_cancelBackgroundImageLoadForState:(UIControlState)state { + [self sd_cancelImageLoadOperationWithKey:backgroundImageOperationKeyForState(state)]; +} + +#pragma mark - Private + +- (SDStateImageURLDictionary *)sd_imageURLStorage { + SDStateImageURLDictionary *storage = objc_getAssociatedObject(self, &imageURLStorageKey); + if (!storage) { + storage = [NSMutableDictionary dictionary]; + objc_setAssociatedObject(self, &imageURLStorageKey, storage, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + + return storage; +} + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/UIImage+ForceDecode.h b/Pods/SDWebImage/SDWebImage/UIImage+ForceDecode.h new file mode 100644 index 0000000..708c37b --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImage+ForceDecode.h @@ -0,0 +1,17 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +@interface UIImage (ForceDecode) + ++ (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image; + ++ (nullable UIImage *)decodedAndScaledDownImageWithImage:(nullable UIImage *)image; + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIImage+ForceDecode.m b/Pods/SDWebImage/SDWebImage/UIImage+ForceDecode.m new file mode 100644 index 0000000..ee55aee --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImage+ForceDecode.m @@ -0,0 +1,30 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIImage+ForceDecode.h" +#import "SDWebImageCodersManager.h" + +@implementation UIImage (ForceDecode) + ++ (UIImage *)decodedImageWithImage:(UIImage *)image { + if (!image) { + return nil; + } + NSData *tempData; + return [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(NO)}]; +} + ++ (UIImage *)decodedAndScaledDownImageWithImage:(UIImage *)image { + if (!image) { + return nil; + } + NSData *tempData; + return [[SDWebImageCodersManager sharedInstance] decompressedImageWithImage:image data:&tempData options:@{SDWebImageCoderScaleDownLargeImagesKey: @(YES)}]; +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIImage+GIF.h b/Pods/SDWebImage/SDWebImage/UIImage+GIF.h new file mode 100644 index 0000000..a3a6646 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImage+GIF.h @@ -0,0 +1,25 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Laurin Brandner + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +@interface UIImage (GIF) + +/** + * Creates an animated UIImage from an NSData. + * For static GIF, will create an UIImage with `images` array set to nil. For animated GIF, will create an UIImage with valid `images` array. + */ ++ (UIImage *)sd_animatedGIFWithData:(NSData *)data; + +/** + * Checks if an UIImage instance is a GIF. Will use the `images` array. + */ +- (BOOL)isGIF; + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIImage+GIF.m b/Pods/SDWebImage/SDWebImage/UIImage+GIF.m new file mode 100644 index 0000000..6fbca7a --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImage+GIF.m @@ -0,0 +1,27 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * (c) Laurin Brandner + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIImage+GIF.h" +#import "SDWebImageGIFCoder.h" +#import "NSImage+WebCache.h" + +@implementation UIImage (GIF) + ++ (UIImage *)sd_animatedGIFWithData:(NSData *)data { + if (!data) { + return nil; + } + return [[SDWebImageGIFCoder sharedCoder] decodedImageWithData:data]; +} + +- (BOOL)isGIF { + return (self.images != nil); +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIImage+MemoryCacheCost.h b/Pods/SDWebImage/SDWebImage/UIImage+MemoryCacheCost.h new file mode 100644 index 0000000..9ecf5b9 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImage+MemoryCacheCost.h @@ -0,0 +1,23 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +@interface UIImage (MemoryCacheCost) + +/** + The memory cache cost for specify image used by image cache. The cost function is the pixles count held in memory. + If you set some associated object to `UIImage`, you can set the custom value to indicate the memory cost. + + For `UIImage`, this method return the single frame pixles count when `image.images` is nil for static image. Retuen full frame pixels count when `image.images` is not nil for animated image. + For `NSImage`, this method return the single frame pixels count because `NSImage` does not store all frames in memory. + @note Note that because of the limitations of categories this property can get out of sync if you create another instance with CGImage or other methods. + */ +@property (assign, nonatomic) NSUInteger sd_memoryCost; + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIImage+MemoryCacheCost.m b/Pods/SDWebImage/SDWebImage/UIImage+MemoryCacheCost.m new file mode 100644 index 0000000..6f1375d --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImage+MemoryCacheCost.m @@ -0,0 +1,38 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIImage+MemoryCacheCost.h" +#import "objc/runtime.h" + +FOUNDATION_STATIC_INLINE NSUInteger SDMemoryCacheCostForImage(UIImage *image) { +#if SD_MAC + return image.size.height * image.size.width; +#elif SD_UIKIT || SD_WATCH + NSUInteger imageSize = image.size.height * image.size.width * image.scale * image.scale; + return image.images ? (imageSize * image.images.count) : imageSize; +#endif +} + +@implementation UIImage (MemoryCacheCost) + +- (NSUInteger)sd_memoryCost { + NSNumber *value = objc_getAssociatedObject(self, @selector(sd_memoryCost)); + NSUInteger memoryCost; + if (value != nil) { + memoryCost = [value unsignedIntegerValue]; + } else { + memoryCost = SDMemoryCacheCostForImage(self); + } + return memoryCost; +} + +- (void)setSd_memoryCost:(NSUInteger)sd_memoryCost { + objc_setAssociatedObject(self, @selector(sd_memoryCost), @(sd_memoryCost), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.h b/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.h new file mode 100644 index 0000000..5c6f473 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.h @@ -0,0 +1,37 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "NSData+ImageContentType.h" + +@interface UIImage (MultiFormat) + +/** + * UIKit: + * For static image format, this value is always 0. + * For animated image format, 0 means infinite looping. + * @note Note that because of the limitations of categories this property can get out of sync if you create another instance with CGImage or other methods. + * AppKit: + * NSImage currently only support animated via GIF imageRep unlike UIImage. + * The getter of this property will get the loop count from GIF imageRep + * The setter of this property will set the loop count from GIF imageRep + */ +@property (nonatomic, assign) NSUInteger sd_imageLoopCount; + +/** + * The image format represent the original compressed image data format. + * If you don't manually specify a format, this information is retrieve from CGImage using `CGImageGetUTType`, which may return nil for non-CG based image. At this time it will return `SDImageFormatUndefined` as default value. + * @note Note that because of the limitations of categories this property can get out of sync if you create another instance with CGImage or other methods. + */ +@property (nonatomic, assign) SDImageFormat sd_imageFormat; + ++ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data; +- (nullable NSData *)sd_imageData; +- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat; + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.m b/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.m new file mode 100644 index 0000000..d3198d2 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImage+MultiFormat.m @@ -0,0 +1,95 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIImage+MultiFormat.h" +#import "NSImage+WebCache.h" +#import "SDWebImageCodersManager.h" +#import "objc/runtime.h" + +@implementation UIImage (MultiFormat) + +#if SD_MAC +- (NSUInteger)sd_imageLoopCount { + NSUInteger imageLoopCount = 0; + for (NSImageRep *rep in self.representations) { + if ([rep isKindOfClass:[NSBitmapImageRep class]]) { + NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; + imageLoopCount = [[bitmapRep valueForProperty:NSImageLoopCount] unsignedIntegerValue]; + break; + } + } + return imageLoopCount; +} + +- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { + for (NSImageRep *rep in self.representations) { + if ([rep isKindOfClass:[NSBitmapImageRep class]]) { + NSBitmapImageRep *bitmapRep = (NSBitmapImageRep *)rep; + [bitmapRep setProperty:NSImageLoopCount withValue:@(sd_imageLoopCount)]; + break; + } + } +} + +#else + +- (NSUInteger)sd_imageLoopCount { + NSUInteger imageLoopCount = 0; + NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageLoopCount)); + if ([value isKindOfClass:[NSNumber class]]) { + imageLoopCount = value.unsignedIntegerValue; + } + return imageLoopCount; +} + +- (void)setSd_imageLoopCount:(NSUInteger)sd_imageLoopCount { + NSNumber *value = @(sd_imageLoopCount); + objc_setAssociatedObject(self, @selector(sd_imageLoopCount), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} +#endif + +- (SDImageFormat)sd_imageFormat { + SDImageFormat imageFormat = SDImageFormatUndefined; + NSNumber *value = objc_getAssociatedObject(self, @selector(sd_imageFormat)); + if ([value isKindOfClass:[NSNumber class]]) { + imageFormat = value.integerValue; + return imageFormat; + } + // Check CGImage's UTType, may return nil for non-Image/IO based image +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + if (&CGImageGetUTType != NULL) { + CFStringRef uttype = CGImageGetUTType(self.CGImage); + imageFormat = [NSData sd_imageFormatFromUTType:uttype]; + } +#pragma clang diagnostic pop + return imageFormat; +} + +- (void)setSd_imageFormat:(SDImageFormat)sd_imageFormat { + objc_setAssociatedObject(self, @selector(sd_imageFormat), @(sd_imageFormat), OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + ++ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data { + return [[SDWebImageCodersManager sharedInstance] decodedImageWithData:data]; +} + +- (nullable NSData *)sd_imageData { + return [self sd_imageDataAsFormat:SDImageFormatUndefined]; +} + +- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat { + NSData *imageData = nil; + if (self) { + imageData = [[SDWebImageCodersManager sharedInstance] encodedDataWithImage:self format:imageFormat]; + } + return imageData; +} + + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.h b/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.h new file mode 100644 index 0000000..c806e5f --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.h @@ -0,0 +1,94 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" + +#if SD_UIKIT + +#import "SDWebImageManager.h" + +/** + * Integrates SDWebImage async downloading and caching of remote images with UIImageView for highlighted state. + */ +@interface UIImageView (HighlightedWebCache) + +/** + * Set the imageView `highlightedImage` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + */ +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `highlightedImage` with an `url` and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `highlightedImage` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url + completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `highlightedImage` with an `url` and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the imageView `highlightedImage` with an `url` and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.m b/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.m new file mode 100644 index 0000000..fb13bd8 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImageView+HighlightedWebCache.m @@ -0,0 +1,52 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIImageView+HighlightedWebCache.h" + +#if SD_UIKIT + +#import "UIView+WebCacheOperation.h" +#import "UIView+WebCache.h" + +@implementation UIImageView (HighlightedWebCache) + +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url { + [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:nil]; +} + +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options { + [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil]; +} + +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:completedBlock]; +} + +- (void)sd_setHighlightedImageWithURL:(nullable NSURL *)url + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock { + __weak typeof(self)weakSelf = self; + [self sd_internalSetImageWithURL:url + placeholderImage:nil + options:options + operationKey:@"UIImageViewImageOperationHighlighted" + setImageBlock:^(UIImage *image, NSData *imageData) { + weakSelf.highlightedImage = image; + } + progress:progressBlock + completed:completedBlock]; +} + +@end + +#endif diff --git a/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.h b/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.h new file mode 100644 index 0000000..d2992cb --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.h @@ -0,0 +1,193 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "SDWebImageManager.h" + +/** + * Integrates SDWebImage async downloading and caching of remote images with UIImageView. + * + * Usage with a UITableViewCell sub-class: + * + * @code + +#import + +... + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *MyIdentifier = @"MyIdentifier"; + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; + + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier]; + } + + // Here we use the provided sd_setImageWithURL: method to load the web image + // Ensure you use a placeholder image otherwise cells will be initialized with no image + [cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://example.com/image.jpg"] + placeholderImage:[UIImage imageNamed:@"placeholder"]]; + + cell.textLabel.text = @"My Text"; + return cell; +} + + * @endcode + */ +@interface UIImageView (WebCache) + +/** + * Set the imageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url` and a placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @see sd_setImageWithURL:placeholderImage:options: + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url`. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + completed:(nullable SDExternalCompletionBlock)completedBlock NS_REFINED_FOR_SWIFT; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url`, placeholder and custom options. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url` and custom options. The placeholder image is from previous cached image and will use the provided one instead if the query failed. + * This method was designed to ensure that placeholder and query cache process happened in the same runloop to avoid flashing on cell during two `setImage:` call. But it's really misunderstanding and deprecated. + * This can be done by using `sd_setImageWithURL:` with `SDWebImageQueryDiskSync`. But take care that if the memory cache missed, query disk cache synchronously may reduce the frame rate + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + * @deprecated consider using `SDWebImageQueryDiskSync` options with `sd_setImageWithURL:` instead + */ +- (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock __deprecated_msg("This method is misunderstanding and deprecated, consider using `SDWebImageQueryDiskSync` options with `sd_setImageWithURL:` instead"); + +#if SD_UIKIT + +#pragma mark - Animation of multiple images + +/** + * Download an array of images and starts them in an animation loop + * + * @param arrayOfURLs An array of NSURL + */ +- (void)sd_setAnimationImagesWithURLs:(nonnull NSArray *)arrayOfURLs; + +- (void)sd_cancelCurrentAnimationImagesLoad; + +#endif + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.m b/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.m new file mode 100644 index 0000000..1baea5d --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIImageView+WebCache.m @@ -0,0 +1,139 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIImageView+WebCache.h" +#import "objc/runtime.h" +#import "UIView+WebCacheOperation.h" +#import "UIView+WebCache.h" + +@implementation UIImageView (WebCache) + +- (void)sd_setImageWithURL:(nullable NSURL *)url { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url placeholderImage:(nullable UIImage *)placeholder options:(SDWebImageOptions)options completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; +} + +- (void)sd_setImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock { + [self sd_internalSetImageWithURL:url + placeholderImage:placeholder + options:options + operationKey:nil + setImageBlock:nil + progress:progressBlock + completed:completedBlock]; +} + +- (void)sd_setImageWithPreviousCachedImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock { + NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url]; + UIImage *lastPreviousCachedImage = [[SDImageCache sharedImageCache] imageFromCacheForKey:key]; + + [self sd_setImageWithURL:url placeholderImage:lastPreviousCachedImage ?: placeholder options:options progress:progressBlock completed:completedBlock]; +} + +#if SD_UIKIT + +#pragma mark - Animation of multiple images + +- (void)sd_setAnimationImagesWithURLs:(nonnull NSArray *)arrayOfURLs { + [self sd_cancelCurrentAnimationImagesLoad]; + NSPointerArray *operationsArray = [self sd_animationOperationArray]; + + [arrayOfURLs enumerateObjectsUsingBlock:^(NSURL *logoImageURL, NSUInteger idx, BOOL * _Nonnull stop) { + __weak __typeof(self) wself = self; + id operation = [[SDWebImageManager sharedManager] loadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + __strong typeof(wself) sself = wself; + if (!sself) return; + dispatch_main_async_safe(^{ + [sself stopAnimating]; + if (sself && image) { + NSMutableArray *currentImages = [[sself animationImages] mutableCopy]; + if (!currentImages) { + currentImages = [[NSMutableArray alloc] init]; + } + + // We know what index objects should be at when they are returned so + // we will put the object at the index, filling any empty indexes + // with the image that was returned too "early". These images will + // be overwritten. (does not require additional sorting datastructure) + while ([currentImages count] < idx) { + [currentImages addObject:image]; + } + + currentImages[idx] = image; + + sself.animationImages = currentImages; + [sself setNeedsLayout]; + } + [sself startAnimating]; + }); + }]; + @synchronized (self) { + [operationsArray addPointer:(__bridge void *)(operation)]; + } + }]; +} + +static char animationLoadOperationKey; + +// element is weak because operation instance is retained by SDWebImageManager's runningOperations property +// we should use lock to keep thread-safe because these method may not be acessed from main queue +- (NSPointerArray *)sd_animationOperationArray { + @synchronized(self) { + NSPointerArray *operationsArray = objc_getAssociatedObject(self, &animationLoadOperationKey); + if (operationsArray) { + return operationsArray; + } + operationsArray = [NSPointerArray weakObjectsPointerArray]; + objc_setAssociatedObject(self, &animationLoadOperationKey, operationsArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + return operationsArray; + } +} + +- (void)sd_cancelCurrentAnimationImagesLoad { + NSPointerArray *operationsArray = [self sd_animationOperationArray]; + if (operationsArray) { + @synchronized (self) { + for (id operation in operationsArray) { + if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) { + [operation cancel]; + } + } + operationsArray.count = 0; + } + } +} +#endif + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIView+WebCache.h b/Pods/SDWebImage/SDWebImage/UIView+WebCache.h new file mode 100644 index 0000000..5cf40ca --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIView+WebCache.h @@ -0,0 +1,140 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "SDWebImageManager.h" +#import "SDWebImageTransition.h" + +/** + A Dispatch group to maintain setImageBlock and completionBlock. This key should be used only internally and may be changed in the future. (dispatch_group_t) + */ +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageInternalSetImageGroupKey; +/** + A SDWebImageManager instance to control the image download and cache process using in UIImageView+WebCache category and likes. If not provided, use the shared manager (SDWebImageManager) + */ +FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageExternalCustomManagerKey; +/** + The value specify that the image progress unit count cannot be determined because the progressBlock is not been called. + */ +FOUNDATION_EXPORT const int64_t SDWebImageProgressUnitCountUnknown; /* 1LL */ + +typedef void(^SDSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable imageData); +typedef void(^SDInternalSetImageBlock)(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL); + +@interface UIView (WebCache) + +/** + * Get the current image URL. + * + * @note Note that because of the limitations of categories this property can get out of sync if you use setImage: directly. + */ +- (nullable NSURL *)sd_imageURL; + +/** + * The current image loading progress associated to the view. The unit count is the received size and excepted size of download. + * The `totalUnitCount` and `completedUnitCount` will be reset to 0 after a new image loading start (change from current queue). And they will be set to `SDWebImageProgressUnitCountUnknown` if the progressBlock not been called but the image loading success to mark the progress finished (change from main queue). + * @note You can use Key-Value Observing on the progress, but you should take care that the change to progress is from a background queue during download(the same as progressBlock). If you want to using KVO and update the UI, make sure to dispatch on the main queue. And it's recommand to use some KVO libs like KVOController because it's more safe and easy to use. + * @note The getter will create a progress instance if the value is nil. You can also set a custom progress instance and let it been updated during image loading + * @note Note that because of the limitations of categories this property can get out of sync if you update the progress directly. + */ +@property (nonatomic, strong, null_resettable) NSProgress *sd_imageProgress; + +/** + * Set the imageView `image` with an `url` and optionally a placeholder image. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param operationKey A string to be used as the operation key. If nil, will use the class name + * @param setImageBlock Block used for custom set image code + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + */ +- (void)sd_internalSetImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + operationKey:(nullable NSString *)operationKey + setImageBlock:(nullable SDSetImageBlock)setImageBlock + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock; + +/** + * Set the imageView `image` with an `url` and optionally a placeholder image. + * + * The download is asynchronous and cached. + * + * @param url The url for the image. + * @param placeholder The image to be set initially, until the image request finishes. + * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. + * @param operationKey A string to be used as the operation key. If nil, will use the class name + * @param setImageBlock Block used for custom set image code + * @param progressBlock A block called while image is downloading + * @note the progress block is executed on a background queue + * @param completedBlock A block called when operation has been completed. This block has no return value + * and takes the requested UIImage as first parameter. In case of error the image parameter + * is nil and the second parameter may contain an NSError. The third parameter is a Boolean + * indicating if the image was retrieved from the local cache or from the network. + * The fourth parameter is the original image url. + * @param context A context with extra information to perform specify changes or processes. + */ +- (void)sd_internalSetImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + operationKey:(nullable NSString *)operationKey + setImageBlock:(nullable SDSetImageBlock)setImageBlock + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock + context:(nullable NSDictionary *)context; + +/** + * Cancel the current image load + */ +- (void)sd_cancelCurrentImageLoad; + +#if SD_UIKIT || SD_MAC + +#pragma mark - Image Transition + +/** + The image transition when image load finished. See `SDWebImageTransition`. + If you specify nil, do not do transition. Defautls to nil. + */ +@property (nonatomic, strong, nullable) SDWebImageTransition *sd_imageTransition; + +#if SD_UIKIT + +#pragma mark - Activity indicator + +/** + * Show activity UIActivityIndicatorView + */ +- (void)sd_setShowActivityIndicatorView:(BOOL)show; + +/** + * set desired UIActivityIndicatorViewStyle + * + * @param style The style of the UIActivityIndicatorView + */ +- (void)sd_setIndicatorStyle:(UIActivityIndicatorViewStyle)style; + +- (BOOL)sd_showActivityIndicatorView; +- (void)sd_addActivityIndicator; +- (void)sd_removeActivityIndicator; + +#endif + +#endif + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIView+WebCache.m b/Pods/SDWebImage/SDWebImage/UIView+WebCache.m new file mode 100644 index 0000000..7167252 --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIView+WebCache.m @@ -0,0 +1,385 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIView+WebCache.h" +#import "objc/runtime.h" +#import "UIView+WebCacheOperation.h" + +NSString * const SDWebImageInternalSetImageGroupKey = @"internalSetImageGroup"; +NSString * const SDWebImageExternalCustomManagerKey = @"externalCustomManager"; + +const int64_t SDWebImageProgressUnitCountUnknown = 1LL; + +static char imageURLKey; + +#if SD_UIKIT +static char TAG_ACTIVITY_INDICATOR; +static char TAG_ACTIVITY_STYLE; +static char TAG_ACTIVITY_SHOW; +#endif + +@implementation UIView (WebCache) + +- (nullable NSURL *)sd_imageURL { + return objc_getAssociatedObject(self, &imageURLKey); +} + +- (NSProgress *)sd_imageProgress { + NSProgress *progress = objc_getAssociatedObject(self, @selector(sd_imageProgress)); + if (!progress) { + progress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; + self.sd_imageProgress = progress; + } + return progress; +} + +- (void)setSd_imageProgress:(NSProgress *)sd_imageProgress { + objc_setAssociatedObject(self, @selector(sd_imageProgress), sd_imageProgress, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (void)sd_internalSetImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + operationKey:(nullable NSString *)operationKey + setImageBlock:(nullable SDSetImageBlock)setImageBlock + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock { + return [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options operationKey:operationKey setImageBlock:setImageBlock progress:progressBlock completed:completedBlock context:nil]; +} + +- (void)sd_internalSetImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + operationKey:(nullable NSString *)operationKey + setImageBlock:(nullable SDSetImageBlock)setImageBlock + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock + context:(nullable NSDictionary *)context { + SDInternalSetImageBlock internalSetImageBlock; + if (setImageBlock) { + internalSetImageBlock = ^(UIImage * _Nullable image, NSData * _Nullable imageData, SDImageCacheType cacheType, NSURL * _Nullable imageURL) { + if (setImageBlock) { + setImageBlock(image, imageData); + } + }; + } + [self sd_internalSetImageWithURL:url placeholderImage:placeholder options:options operationKey:operationKey internalSetImageBlock:internalSetImageBlock progress:progressBlock completed:completedBlock context:context]; +} + +- (void)sd_internalSetImageWithURL:(nullable NSURL *)url + placeholderImage:(nullable UIImage *)placeholder + options:(SDWebImageOptions)options + operationKey:(nullable NSString *)operationKey + internalSetImageBlock:(nullable SDInternalSetImageBlock)setImageBlock + progress:(nullable SDWebImageDownloaderProgressBlock)progressBlock + completed:(nullable SDExternalCompletionBlock)completedBlock + context:(nullable NSDictionary *)context { + NSString *validOperationKey = operationKey ?: NSStringFromClass([self class]); + [self sd_cancelImageLoadOperationWithKey:validOperationKey]; + objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + dispatch_group_t group = context[SDWebImageInternalSetImageGroupKey]; + if (!(options & SDWebImageDelayPlaceholder)) { + if (group) { + dispatch_group_enter(group); + } + dispatch_main_async_safe(^{ + [self sd_setImage:placeholder imageData:nil basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:SDImageCacheTypeNone imageURL:url]; + }); + } + + if (url) { +#if SD_UIKIT + // check if activityView is enabled or not + if ([self sd_showActivityIndicatorView]) { + [self sd_addActivityIndicator]; + } +#endif + + // reset the progress + self.sd_imageProgress.totalUnitCount = 0; + self.sd_imageProgress.completedUnitCount = 0; + + SDWebImageManager *manager = [context objectForKey:SDWebImageExternalCustomManagerKey]; + if (!manager) { + manager = [SDWebImageManager sharedManager]; + } + + __weak __typeof(self)wself = self; + SDWebImageDownloaderProgressBlock combinedProgressBlock = ^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { + wself.sd_imageProgress.totalUnitCount = expectedSize; + wself.sd_imageProgress.completedUnitCount = receivedSize; + if (progressBlock) { + progressBlock(receivedSize, expectedSize, targetURL); + } + }; + id operation = [manager loadImageWithURL:url options:options progress:combinedProgressBlock completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { + __strong __typeof (wself) sself = wself; + if (!sself) { return; } +#if SD_UIKIT + [sself sd_removeActivityIndicator]; +#endif + // if the progress not been updated, mark it to complete state + if (finished && !error && sself.sd_imageProgress.totalUnitCount == 0 && sself.sd_imageProgress.completedUnitCount == 0) { + sself.sd_imageProgress.totalUnitCount = SDWebImageProgressUnitCountUnknown; + sself.sd_imageProgress.completedUnitCount = SDWebImageProgressUnitCountUnknown; + } + BOOL shouldCallCompletedBlock = finished || (options & SDWebImageAvoidAutoSetImage); + BOOL shouldNotSetImage = ((image && (options & SDWebImageAvoidAutoSetImage)) || + (!image && !(options & SDWebImageDelayPlaceholder))); + SDWebImageNoParamsBlock callCompletedBlockClojure = ^{ + if (!sself) { return; } + if (!shouldNotSetImage) { + [sself sd_setNeedsLayout]; + } + if (completedBlock && shouldCallCompletedBlock) { + completedBlock(image, error, cacheType, url); + } + }; + + // case 1a: we got an image, but the SDWebImageAvoidAutoSetImage flag is set + // OR + // case 1b: we got no image and the SDWebImageDelayPlaceholder is not set + if (shouldNotSetImage) { + dispatch_main_async_safe(callCompletedBlockClojure); + return; + } + + UIImage *targetImage = nil; + NSData *targetData = nil; + if (image) { + // case 2a: we got an image and the SDWebImageAvoidAutoSetImage is not set + targetImage = image; + targetData = data; + } else if (options & SDWebImageDelayPlaceholder) { + // case 2b: we got no image and the SDWebImageDelayPlaceholder flag is set + targetImage = placeholder; + targetData = nil; + } + +#if SD_UIKIT || SD_MAC + // check whether we should use the image transition + SDWebImageTransition *transition = nil; + if (finished && (options & SDWebImageForceTransition || cacheType == SDImageCacheTypeNone)) { + transition = sself.sd_imageTransition; + } +#endif + dispatch_main_async_safe(^{ + if (group) { + dispatch_group_enter(group); + } +#if SD_UIKIT || SD_MAC + [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:transition cacheType:cacheType imageURL:imageURL]; +#else + [sself sd_setImage:targetImage imageData:targetData basedOnClassOrViaCustomSetImageBlock:setImageBlock cacheType:cacheType imageURL:imageURL]; +#endif + if (group) { + // compatible code for FLAnimatedImage, because we assume completedBlock called after image was set. This will be removed in 5.x + BOOL shouldUseGroup = [objc_getAssociatedObject(group, &SDWebImageInternalSetImageGroupKey) boolValue]; + if (shouldUseGroup) { + dispatch_group_notify(group, dispatch_get_main_queue(), callCompletedBlockClojure); + } else { + callCompletedBlockClojure(); + } + } else { + callCompletedBlockClojure(); + } + }); + }]; + [self sd_setImageLoadOperation:operation forKey:validOperationKey]; + } else { + dispatch_main_async_safe(^{ +#if SD_UIKIT + [self sd_removeActivityIndicator]; +#endif + if (completedBlock) { + NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; + completedBlock(nil, error, SDImageCacheTypeNone, url); + } + }); + } +} + +- (void)sd_cancelCurrentImageLoad { + [self sd_cancelImageLoadOperationWithKey:NSStringFromClass([self class])]; +} + +- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDInternalSetImageBlock)setImageBlock cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL { +#if SD_UIKIT || SD_MAC + [self sd_setImage:image imageData:imageData basedOnClassOrViaCustomSetImageBlock:setImageBlock transition:nil cacheType:cacheType imageURL:imageURL]; +#else + // watchOS does not support view transition. Simplify the logic + if (setImageBlock) { + setImageBlock(image, imageData, cacheType, imageURL); + } else if ([self isKindOfClass:[UIImageView class]]) { + UIImageView *imageView = (UIImageView *)self; + [imageView setImage:image]; + } +#endif +} + +#if SD_UIKIT || SD_MAC +- (void)sd_setImage:(UIImage *)image imageData:(NSData *)imageData basedOnClassOrViaCustomSetImageBlock:(SDInternalSetImageBlock)setImageBlock transition:(SDWebImageTransition *)transition cacheType:(SDImageCacheType)cacheType imageURL:(NSURL *)imageURL { + UIView *view = self; + SDInternalSetImageBlock finalSetImageBlock; + if (setImageBlock) { + finalSetImageBlock = setImageBlock; + } else if ([view isKindOfClass:[UIImageView class]]) { + UIImageView *imageView = (UIImageView *)view; + finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData, SDImageCacheType setCacheType, NSURL *setImageURL) { + imageView.image = setImage; + }; + } +#if SD_UIKIT + else if ([view isKindOfClass:[UIButton class]]) { + UIButton *button = (UIButton *)view; + finalSetImageBlock = ^(UIImage *setImage, NSData *setImageData, SDImageCacheType setCacheType, NSURL *setImageURL) { + [button setImage:setImage forState:UIControlStateNormal]; + }; + } +#endif + + if (transition) { +#if SD_UIKIT + [UIView transitionWithView:view duration:0 options:0 animations:^{ + // 0 duration to let UIKit render placeholder and prepares block + if (transition.prepares) { + transition.prepares(view, image, imageData, cacheType, imageURL); + } + } completion:^(BOOL finished) { + [UIView transitionWithView:view duration:transition.duration options:transition.animationOptions animations:^{ + if (finalSetImageBlock && !transition.avoidAutoSetImage) { + finalSetImageBlock(image, imageData, cacheType, imageURL); + } + if (transition.animations) { + transition.animations(view, image); + } + } completion:transition.completion]; + }]; +#elif SD_MAC + [NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull prepareContext) { + // 0 duration to let AppKit render placeholder and prepares block + prepareContext.duration = 0; + if (transition.prepares) { + transition.prepares(view, image, imageData, cacheType, imageURL); + } + } completionHandler:^{ + [NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) { + context.duration = transition.duration; + context.timingFunction = transition.timingFunction; + context.allowsImplicitAnimation = (transition.animationOptions & SDWebImageAnimationOptionAllowsImplicitAnimation); + if (finalSetImageBlock && !transition.avoidAutoSetImage) { + finalSetImageBlock(image, imageData, cacheType, imageURL); + } + if (transition.animations) { + transition.animations(view, image); + } + } completionHandler:^{ + if (transition.completion) { + transition.completion(YES); + } + }]; + }]; +#endif + } else { + if (finalSetImageBlock) { + finalSetImageBlock(image, imageData, cacheType, imageURL); + } + } +} +#endif + +- (void)sd_setNeedsLayout { +#if SD_UIKIT + [self setNeedsLayout]; +#elif SD_MAC + [self setNeedsLayout:YES]; +#elif SD_WATCH + // Do nothing because WatchKit automatically layout the view after property change +#endif +} + +#if SD_UIKIT || SD_MAC + +#pragma mark - Image Transition +- (SDWebImageTransition *)sd_imageTransition { + return objc_getAssociatedObject(self, @selector(sd_imageTransition)); +} + +- (void)setSd_imageTransition:(SDWebImageTransition *)sd_imageTransition { + objc_setAssociatedObject(self, @selector(sd_imageTransition), sd_imageTransition, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +#if SD_UIKIT + +#pragma mark - Activity indicator +- (UIActivityIndicatorView *)activityIndicator { + return (UIActivityIndicatorView *)objc_getAssociatedObject(self, &TAG_ACTIVITY_INDICATOR); +} + +- (void)setActivityIndicator:(UIActivityIndicatorView *)activityIndicator { + objc_setAssociatedObject(self, &TAG_ACTIVITY_INDICATOR, activityIndicator, OBJC_ASSOCIATION_RETAIN); +} + +- (void)sd_setShowActivityIndicatorView:(BOOL)show { + objc_setAssociatedObject(self, &TAG_ACTIVITY_SHOW, @(show), OBJC_ASSOCIATION_RETAIN); +} + +- (BOOL)sd_showActivityIndicatorView { + return [objc_getAssociatedObject(self, &TAG_ACTIVITY_SHOW) boolValue]; +} + +- (void)sd_setIndicatorStyle:(UIActivityIndicatorViewStyle)style{ + objc_setAssociatedObject(self, &TAG_ACTIVITY_STYLE, [NSNumber numberWithInteger:style], OBJC_ASSOCIATION_RETAIN); +} + +- (int)sd_getIndicatorStyle{ + return [objc_getAssociatedObject(self, &TAG_ACTIVITY_STYLE) intValue]; +} + +- (void)sd_addActivityIndicator { + dispatch_main_async_safe(^{ + if (!self.activityIndicator) { + self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:[self sd_getIndicatorStyle]]; + self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO; + + [self addSubview:self.activityIndicator]; + + [self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeCenterX + multiplier:1.0 + constant:0.0]]; + [self addConstraint:[NSLayoutConstraint constraintWithItem:self.activityIndicator + attribute:NSLayoutAttributeCenterY + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeCenterY + multiplier:1.0 + constant:0.0]]; + } + [self.activityIndicator startAnimating]; + }); +} + +- (void)sd_removeActivityIndicator { + dispatch_main_async_safe(^{ + if (self.activityIndicator) { + [self.activityIndicator removeFromSuperview]; + self.activityIndicator = nil; + } + }); +} + +#endif + +#endif + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.h b/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.h new file mode 100644 index 0000000..0be284b --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.h @@ -0,0 +1,38 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "SDWebImageCompat.h" +#import "SDWebImageOperation.h" + +// These methods are used to support canceling for UIView image loading, it's designed to be used internal but not external. +// All the stored operations are weak, so it will be dalloced after image loading finished. If you need to store operations, use your own class to keep a strong reference for them. +@interface UIView (WebCacheOperation) + +/** + * Set the image load operation (storage in a UIView based weak map table) + * + * @param operation the operation + * @param key key for storing the operation + */ +- (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key; + +/** + * Cancel all operations for the current UIView and key + * + * @param key key for identifying the operations + */ +- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key; + +/** + * Just remove the operations corresponding to the current UIView and key without cancelling them + * + * @param key key for identifying the operations + */ +- (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key; + +@end diff --git a/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.m b/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.m new file mode 100644 index 0000000..cd769be --- /dev/null +++ b/Pods/SDWebImage/SDWebImage/UIView+WebCacheOperation.m @@ -0,0 +1,73 @@ +/* + * This file is part of the SDWebImage package. + * (c) Olivier Poitrey + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#import "UIView+WebCacheOperation.h" +#import "objc/runtime.h" + +static char loadOperationKey; + +// key is copy, value is weak because operation instance is retained by SDWebImageManager's runningOperations property +// we should use lock to keep thread-safe because these method may not be acessed from main queue +typedef NSMapTable> SDOperationsDictionary; + +@implementation UIView (WebCacheOperation) + +- (SDOperationsDictionary *)sd_operationDictionary { + @synchronized(self) { + SDOperationsDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey); + if (operations) { + return operations; + } + operations = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory capacity:0]; + objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + return operations; + } +} + +- (void)sd_setImageLoadOperation:(nullable id)operation forKey:(nullable NSString *)key { + if (key) { + [self sd_cancelImageLoadOperationWithKey:key]; + if (operation) { + SDOperationsDictionary *operationDictionary = [self sd_operationDictionary]; + @synchronized (self) { + [operationDictionary setObject:operation forKey:key]; + } + } + } +} + +- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key { + if (key) { + // Cancel in progress downloader from queue + SDOperationsDictionary *operationDictionary = [self sd_operationDictionary]; + id operation; + + @synchronized (self) { + operation = [operationDictionary objectForKey:key]; + } + if (operation) { + if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]) { + [operation cancel]; + } + @synchronized (self) { + [operationDictionary removeObjectForKey:key]; + } + } + } +} + +- (void)sd_removeImageLoadOperationWithKey:(nullable NSString *)key { + if (key) { + SDOperationsDictionary *operationDictionary = [self sd_operationDictionary]; + @synchronized (self) { + [operationDictionary removeObjectForKey:key]; + } + } +} + +@end diff --git a/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-Info.plist b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-Info.plist new file mode 100644 index 0000000..bb5a9ff --- /dev/null +++ b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 4.9.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-dummy.m b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-dummy.m new file mode 100644 index 0000000..e1abb30 --- /dev/null +++ b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Alamofire_iOS : NSObject +@end +@implementation PodsDummy_Alamofire_iOS +@end diff --git a/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-prefix.pch b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-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/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-umbrella.h b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-umbrella.h new file mode 100644 index 0000000..00014e3 --- /dev/null +++ b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS-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/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS.modulemap b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS.modulemap new file mode 100644 index 0000000..ce21525 --- /dev/null +++ b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS.modulemap @@ -0,0 +1,6 @@ +framework module Alamofire { + umbrella header "Alamofire-iOS-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS.xcconfig b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS.xcconfig new file mode 100644 index 0000000..d5fc108 --- /dev/null +++ b/Pods/Target Support Files/Alamofire-iOS/Alamofire-iOS.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-iOS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +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 +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-Info.plist b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-Info.plist new file mode 100644 index 0000000..bb5a9ff --- /dev/null +++ b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 4.9.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-dummy.m b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-dummy.m new file mode 100644 index 0000000..8a0f66d --- /dev/null +++ b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Alamofire_watchOS : NSObject +@end +@implementation PodsDummy_Alamofire_watchOS +@end diff --git a/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-prefix.pch b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-prefix.pch new file mode 100644 index 0000000..e33fc32 --- /dev/null +++ b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-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/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-umbrella.h b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-umbrella.h new file mode 100644 index 0000000..0d8e6bd --- /dev/null +++ b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS-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/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS.modulemap b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS.modulemap new file mode 100644 index 0000000..f60c673 --- /dev/null +++ b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS.modulemap @@ -0,0 +1,6 @@ +framework module Alamofire { + umbrella header "Alamofire-watchOS-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS.xcconfig b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS.xcconfig new file mode 100644 index 0000000..c257ef5 --- /dev/null +++ b/Pods/Target Support Files/Alamofire-watchOS/Alamofire-watchOS.xcconfig @@ -0,0 +1,11 @@ +APPLICATION_EXTENSION_API_ONLY = YES +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-watchOS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +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 +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-Info.plist b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-Info.plist new file mode 100644 index 0000000..6daaad1 --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-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.2.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-dummy.m b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-dummy.m new file mode 100644 index 0000000..cdfe5e5 --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_AlamofireObjectMapper_iOS : NSObject +@end +@implementation PodsDummy_AlamofireObjectMapper_iOS +@end diff --git a/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-prefix.pch b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-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/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-umbrella.h b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-umbrella.h new file mode 100644 index 0000000..39f5a35 --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS-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 AlamofireObjectMapperVersionNumber; +FOUNDATION_EXPORT const unsigned char AlamofireObjectMapperVersionString[]; + diff --git a/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS.modulemap b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS.modulemap new file mode 100644 index 0000000..cddfbd4 --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS.modulemap @@ -0,0 +1,6 @@ +framework module AlamofireObjectMapper { + umbrella header "AlamofireObjectMapper-iOS-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS.xcconfig b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS.xcconfig new file mode 100644 index 0000000..6ac8b2d --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-iOS/AlamofireObjectMapper-iOS.xcconfig @@ -0,0 +1,11 @@ +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/AlamofireObjectMapper-iOS +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-iOS" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +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}/AlamofireObjectMapper +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-Info.plist b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-Info.plist new file mode 100644 index 0000000..6daaad1 --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-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.2.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-dummy.m b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-dummy.m new file mode 100644 index 0000000..499e950 --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_AlamofireObjectMapper_watchOS : NSObject +@end +@implementation PodsDummy_AlamofireObjectMapper_watchOS +@end diff --git a/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-prefix.pch b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-prefix.pch new file mode 100644 index 0000000..e33fc32 --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-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/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-umbrella.h b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-umbrella.h new file mode 100644 index 0000000..af350d3 --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS-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 AlamofireObjectMapperVersionNumber; +FOUNDATION_EXPORT const unsigned char AlamofireObjectMapperVersionString[]; + diff --git a/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.modulemap b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.modulemap new file mode 100644 index 0000000..e9637be --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.modulemap @@ -0,0 +1,6 @@ +framework module AlamofireObjectMapper { + umbrella header "AlamofireObjectMapper-watchOS-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.xcconfig b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.xcconfig new file mode 100644 index 0000000..c37eb2a --- /dev/null +++ b/Pods/Target Support Files/AlamofireObjectMapper-watchOS/AlamofireObjectMapper-watchOS.xcconfig @@ -0,0 +1,12 @@ +APPLICATION_EXTENSION_API_ONLY = YES +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/AlamofireObjectMapper-watchOS +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-watchOS" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-watchOS" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +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}/AlamofireObjectMapper +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-Info.plist b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-Info.plist new file mode 100644 index 0000000..bfb8987 --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.1.3 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-dummy.m b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-dummy.m new file mode 100644 index 0000000..0602f45 --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_CryptoSwift_iOS : NSObject +@end +@implementation PodsDummy_CryptoSwift_iOS +@end diff --git a/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-prefix.pch b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-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/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-umbrella.h b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-umbrella.h new file mode 100644 index 0000000..e93efa8 --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS-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 CryptoSwiftVersionNumber; +FOUNDATION_EXPORT const unsigned char CryptoSwiftVersionString[]; + diff --git a/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS.modulemap b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS.modulemap new file mode 100644 index 0000000..2e5a99a --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS.modulemap @@ -0,0 +1,6 @@ +framework module CryptoSwift { + umbrella header "CryptoSwift-iOS-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS.xcconfig b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS.xcconfig new file mode 100644 index 0000000..223b5f3 --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-iOS/CryptoSwift-iOS.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/CryptoSwift-iOS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +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}/CryptoSwift +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-Info.plist b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-Info.plist new file mode 100644 index 0000000..bfb8987 --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.1.3 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-dummy.m b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-dummy.m new file mode 100644 index 0000000..a834386 --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_CryptoSwift_watchOS : NSObject +@end +@implementation PodsDummy_CryptoSwift_watchOS +@end diff --git a/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-prefix.pch b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-prefix.pch new file mode 100644 index 0000000..e33fc32 --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-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/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-umbrella.h b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-umbrella.h new file mode 100644 index 0000000..140ad71 --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS-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 CryptoSwiftVersionNumber; +FOUNDATION_EXPORT const unsigned char CryptoSwiftVersionString[]; + diff --git a/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS.modulemap b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS.modulemap new file mode 100644 index 0000000..a1573d2 --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS.modulemap @@ -0,0 +1,6 @@ +framework module CryptoSwift { + umbrella header "CryptoSwift-watchOS-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS.xcconfig b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS.xcconfig new file mode 100644 index 0000000..0b107bb --- /dev/null +++ b/Pods/Target Support Files/CryptoSwift-watchOS/CryptoSwift-watchOS.xcconfig @@ -0,0 +1,11 @@ +APPLICATION_EXTENSION_API_ONLY = YES +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/CryptoSwift-watchOS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +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}/CryptoSwift +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-Info.plist b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-Info.plist new file mode 100644 index 0000000..0c0463f --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 3.5.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-dummy.m b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-dummy.m new file mode 100644 index 0000000..dfab7f4 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_ObjectMapper_iOS : NSObject +@end +@implementation PodsDummy_ObjectMapper_iOS +@end diff --git a/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-prefix.pch b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-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/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-umbrella.h b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-umbrella.h new file mode 100644 index 0000000..e993e40 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS-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 ObjectMapperVersionNumber; +FOUNDATION_EXPORT const unsigned char ObjectMapperVersionString[]; + diff --git a/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS.modulemap b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS.modulemap new file mode 100644 index 0000000..83d65a5 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS.modulemap @@ -0,0 +1,6 @@ +framework module ObjectMapper { + umbrella header "ObjectMapper-iOS-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS.xcconfig b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS.xcconfig new file mode 100644 index 0000000..62f9347 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-iOS/ObjectMapper-iOS.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-iOS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +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}/ObjectMapper +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-Info.plist b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-Info.plist new file mode 100644 index 0000000..0c0463f --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 3.5.1 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-dummy.m b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-dummy.m new file mode 100644 index 0000000..8096c39 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_ObjectMapper_watchOS : NSObject +@end +@implementation PodsDummy_ObjectMapper_watchOS +@end diff --git a/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-prefix.pch b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-prefix.pch new file mode 100644 index 0000000..e33fc32 --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-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/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-umbrella.h b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-umbrella.h new file mode 100644 index 0000000..c18650d --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS-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 ObjectMapperVersionNumber; +FOUNDATION_EXPORT const unsigned char ObjectMapperVersionString[]; + diff --git a/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS.modulemap b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS.modulemap new file mode 100644 index 0000000..679975d --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS.modulemap @@ -0,0 +1,6 @@ +framework module ObjectMapper { + umbrella header "ObjectMapper-watchOS-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS.xcconfig b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS.xcconfig new file mode 100644 index 0000000..c34a49e --- /dev/null +++ b/Pods/Target Support Files/ObjectMapper-watchOS/ObjectMapper-watchOS.xcconfig @@ -0,0 +1,11 @@ +APPLICATION_EXTENSION_API_ONLY = YES +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-watchOS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +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}/ObjectMapper +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-Info.plist b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-acknowledgements.markdown b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-acknowledgements.markdown new file mode 100644 index 0000000..741125d --- /dev/null +++ b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-acknowledgements.markdown @@ -0,0 +1,127 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## Alamofire + +Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +## AlamofireObjectMapper + +The MIT License (MIT) + +Copyright (c) 2015 Tristan Himmelman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +## CryptoSwift + +Copyright (C) 2014-2017 Marcin Krzyżanowski +This software is provided 'as-is', without any express or implied warranty. + +In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +- This notice may not be removed or altered from any source or binary distribution. +- Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).' + + +## ObjectMapper + +The MIT License (MIT) +Copyright (c) 2014 Hearst + +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. + + +## SDWebImage + +Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com + +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. + + + +## Toast-Swift + +Copyright (c) 2015-2017 Charles Scalesse. + +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. + +Generated by CocoaPods - https://cocoapods.org diff --git a/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-acknowledgements.plist b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-acknowledgements.plist new file mode 100644 index 0000000..31ff40e --- /dev/null +++ b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-acknowledgements.plist @@ -0,0 +1,189 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + License + MIT + Title + Alamofire + Type + PSGroupSpecifier + + + FooterText + The MIT License (MIT) + +Copyright (c) 2015 Tristan Himmelman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + License + MIT + Title + AlamofireObjectMapper + Type + PSGroupSpecifier + + + FooterText + Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com> +This software is provided 'as-is', without any express or implied warranty. + +In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +- This notice may not be removed or altered from any source or binary distribution. +- Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).' + + License + Attribution + Title + CryptoSwift + Type + PSGroupSpecifier + + + FooterText + The MIT License (MIT) +Copyright (c) 2014 Hearst + +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 + ObjectMapper + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com + +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 + SDWebImage + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2015-2017 Charles Scalesse. + +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 + Toast-Swift + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-dummy.m b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-dummy.m new file mode 100644 index 0000000..aac6d49 --- /dev/null +++ b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_BSRadioWaves : NSObject +@end +@implementation PodsDummy_Pods_BSRadioWaves +@end diff --git a/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh new file mode 100755 index 0000000..fe05e8d --- /dev/null +++ b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-frameworks.sh @@ -0,0 +1,181 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + +if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then + # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy + # frameworks to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +# Used as a return value for each invocation of `strip_invalid_archs` function. +STRIP_BINARY_RETVAL=0 + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +# Copies and strips a vendored framework +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + elif [ -L "${binary}" ]; then + echo "Destination binary is symlinked..." + dirname="$(dirname "${binary}")" + binary="${dirname}/$(readlink "${binary}")" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} + +# Copies and strips a vendored dSYM +install_dsym() { + local source="$1" + if [ -r "$source" ]; then + # Copy the dSYM into a the targets temp dir. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" + + local basename + basename="$(basename -s .framework.dSYM "$source")" + binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then + strip_invalid_archs "$binary" + fi + + if [[ $STRIP_BINARY_RETVAL == 1 ]]; then + # Move the stripped file into its final destination. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" + else + # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. + touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" + fi + fi +} + +# Copies the bcsymbolmap files of a vendored framework +install_bcsymbolmap() { + local bcsymbolmap_path="$1" + local destination="${BUILT_PRODUCTS_DIR}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identity + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" + + if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + code_sign_cmd="$code_sign_cmd &" + fi + echo "$code_sign_cmd" + eval "$code_sign_cmd" + fi +} + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + # Get architectures for current target binary + binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" + # Intersect them with the architectures we are building for + intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" + # If there are no archs supported by this binary then warn the user + if [[ -z "$intersected_archs" ]]; then + echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." + STRIP_BINARY_RETVAL=0 + return + fi + stripped="" + for arch in $binary_archs; do + if ! [[ "${ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi + STRIP_BINARY_RETVAL=1 +} + + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/Alamofire-iOS/Alamofire.framework" + install_framework "${BUILT_PRODUCTS_DIR}/AlamofireObjectMapper-iOS/AlamofireObjectMapper.framework" + install_framework "${BUILT_PRODUCTS_DIR}/CryptoSwift-iOS/CryptoSwift.framework" + install_framework "${BUILT_PRODUCTS_DIR}/ObjectMapper-iOS/ObjectMapper.framework" + install_framework "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework" + install_framework "${BUILT_PRODUCTS_DIR}/Toast-Swift/Toast_Swift.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/Alamofire-iOS/Alamofire.framework" + install_framework "${BUILT_PRODUCTS_DIR}/AlamofireObjectMapper-iOS/AlamofireObjectMapper.framework" + install_framework "${BUILT_PRODUCTS_DIR}/CryptoSwift-iOS/CryptoSwift.framework" + install_framework "${BUILT_PRODUCTS_DIR}/ObjectMapper-iOS/ObjectMapper.framework" + install_framework "${BUILT_PRODUCTS_DIR}/SDWebImage-iOS/SDWebImage.framework" + install_framework "${BUILT_PRODUCTS_DIR}/Toast-Swift/Toast_Swift.framework" +fi +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-umbrella.h b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-umbrella.h new file mode 100644 index 0000000..3522913 --- /dev/null +++ b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves-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 Pods_BSRadioWavesVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_BSRadioWavesVersionString[]; + diff --git a/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.debug.xcconfig b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.debug.xcconfig new file mode 100644 index 0000000..d04d3ff --- /dev/null +++ b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.debug.xcconfig @@ -0,0 +1,12 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/AlamofireObjectMapper-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/CryptoSwift-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/Toast-Swift" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-iOS/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/AlamofireObjectMapper-iOS/AlamofireObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CryptoSwift-iOS/CryptoSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-iOS/ObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage-iOS/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Toast-Swift/Toast_Swift.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "AlamofireObjectMapper" -framework "CryptoSwift" -framework "ImageIO" -framework "ObjectMapper" -framework "QuartzCore" -framework "SDWebImage" -framework "Toast_Swift" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.modulemap b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.modulemap new file mode 100644 index 0000000..195a4be --- /dev/null +++ b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.modulemap @@ -0,0 +1,6 @@ +framework module Pods_BSRadioWaves { + umbrella header "Pods-BSRadioWaves-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.release.xcconfig b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.release.xcconfig new file mode 100644 index 0000000..d04d3ff --- /dev/null +++ b/Pods/Target Support Files/Pods-BSRadioWaves/Pods-BSRadioWaves.release.xcconfig @@ -0,0 +1,12 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/AlamofireObjectMapper-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/CryptoSwift-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage-iOS" "${PODS_CONFIGURATION_BUILD_DIR}/Toast-Swift" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-iOS/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/AlamofireObjectMapper-iOS/AlamofireObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CryptoSwift-iOS/CryptoSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-iOS/ObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage-iOS/SDWebImage.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Toast-Swift/Toast_Swift.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "AlamofireObjectMapper" -framework "CryptoSwift" -framework "ImageIO" -framework "ObjectMapper" -framework "QuartzCore" -framework "SDWebImage" -framework "Toast_Swift" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-Info.plist b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-Info.plist new file mode 100644 index 0000000..2243fe6 --- /dev/null +++ b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-acknowledgements.markdown b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-acknowledgements.markdown new file mode 100644 index 0000000..c6e522f --- /dev/null +++ b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-acknowledgements.markdown @@ -0,0 +1,103 @@ +# Acknowledgements +This application makes use of the following third party libraries: + +## Alamofire + +Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + +## AlamofireObjectMapper + +The MIT License (MIT) + +Copyright (c) 2015 Tristan Himmelman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + +## CryptoSwift + +Copyright (C) 2014-2017 Marcin Krzyżanowski +This software is provided 'as-is', without any express or implied warranty. + +In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +- This notice may not be removed or altered from any source or binary distribution. +- Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).' + + +## ObjectMapper + +The MIT License (MIT) +Copyright (c) 2014 Hearst + +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. + + +## SDWebImage + +Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com + +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. + + +Generated by CocoaPods - https://cocoapods.org diff --git a/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-acknowledgements.plist b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-acknowledgements.plist new file mode 100644 index 0000000..0465f15 --- /dev/null +++ b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-acknowledgements.plist @@ -0,0 +1,159 @@ + + + + + PreferenceSpecifiers + + + FooterText + This application makes use of the following third party libraries: + Title + Acknowledgements + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2014 Alamofire Software Foundation (http://alamofire.org/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + License + MIT + Title + Alamofire + Type + PSGroupSpecifier + + + FooterText + The MIT License (MIT) + +Copyright (c) 2015 Tristan Himmelman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + + License + MIT + Title + AlamofireObjectMapper + Type + PSGroupSpecifier + + + FooterText + Copyright (C) 2014-2017 Marcin Krzyżanowski <marcin.krzyzanowski@gmail.com> +This software is provided 'as-is', without any express or implied warranty. + +In no event will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose,including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: + +- The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation is required. +- Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +- This notice may not be removed or altered from any source or binary distribution. +- Redistributions of any form whatsoever must retain the following acknowledgment: 'This product includes software developed by the "Marcin Krzyzanowski" (http://krzyzanowskim.com/).' + + License + Attribution + Title + CryptoSwift + Type + PSGroupSpecifier + + + FooterText + The MIT License (MIT) +Copyright (c) 2014 Hearst + +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 + ObjectMapper + Type + PSGroupSpecifier + + + FooterText + Copyright (c) 2009-2017 Olivier Poitrey rs@dailymotion.com + +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 + SDWebImage + Type + PSGroupSpecifier + + + FooterText + Generated by CocoaPods - https://cocoapods.org + Title + + Type + PSGroupSpecifier + + + StringsTable + Acknowledgements + Title + Acknowledgements + + diff --git a/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-dummy.m b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-dummy.m new file mode 100644 index 0000000..800137e --- /dev/null +++ b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Pods_Watch_Extension : NSObject +@end +@implementation PodsDummy_Pods_Watch_Extension +@end diff --git a/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh new file mode 100755 index 0000000..ed53436 --- /dev/null +++ b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-frameworks.sh @@ -0,0 +1,179 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + +if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then + # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy + # frameworks to, so exit 0 (signalling the script phase was successful). + exit 0 +fi + +echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" +mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + +COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" +SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" + +# Used as a return value for each invocation of `strip_invalid_archs` function. +STRIP_BINARY_RETVAL=0 + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + +# Copies and strips a vendored framework +install_framework() +{ + if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then + local source="${BUILT_PRODUCTS_DIR}/$1" + elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then + local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" + elif [ -r "$1" ]; then + local source="$1" + fi + + local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" + + if [ -L "${source}" ]; then + echo "Symlinked..." + source="$(readlink "${source}")" + fi + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" + + local basename + basename="$(basename -s .framework "$1")" + binary="${destination}/${basename}.framework/${basename}" + + if ! [ -r "$binary" ]; then + binary="${destination}/${basename}" + elif [ -L "${binary}" ]; then + echo "Destination binary is symlinked..." + dirname="$(dirname "${binary}")" + binary="${dirname}/$(readlink "${binary}")" + fi + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then + strip_invalid_archs "$binary" + fi + + # Resign the code if required by the build settings to avoid unstable apps + code_sign_if_enabled "${destination}/$(basename "$1")" + + # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. + if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then + local swift_runtime_libs + swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) + for lib in $swift_runtime_libs; do + echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" + rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" + code_sign_if_enabled "${destination}/${lib}" + done + fi +} + +# Copies and strips a vendored dSYM +install_dsym() { + local source="$1" + if [ -r "$source" ]; then + # Copy the dSYM into a the targets temp dir. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" + + local basename + basename="$(basename -s .framework.dSYM "$source")" + binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}" + + # Strip invalid architectures so "fat" simulator / device frameworks work on device + if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then + strip_invalid_archs "$binary" + fi + + if [[ $STRIP_BINARY_RETVAL == 1 ]]; then + # Move the stripped file into its final destination. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}" + else + # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. + touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM" + fi + fi +} + +# Copies the bcsymbolmap files of a vendored framework +install_bcsymbolmap() { + local bcsymbolmap_path="$1" + local destination="${BUILT_PRODUCTS_DIR}" + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" +} + +# Signs a framework with the provided identity +code_sign_if_enabled() { + if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then + # Use the current code_sign_identity + echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" + local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" + + if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + code_sign_cmd="$code_sign_cmd &" + fi + echo "$code_sign_cmd" + eval "$code_sign_cmd" + fi +} + +# Strip invalid architectures +strip_invalid_archs() { + binary="$1" + # Get architectures for current target binary + binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" + # Intersect them with the architectures we are building for + intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" + # If there are no archs supported by this binary then warn the user + if [[ -z "$intersected_archs" ]]; then + echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." + STRIP_BINARY_RETVAL=0 + return + fi + stripped="" + for arch in $binary_archs; do + if ! [[ "${ARCHS}" == *"$arch"* ]]; then + # Strip non-valid architectures in-place + lipo -remove "$arch" -output "$binary" "$binary" + stripped="$stripped $arch" + fi + done + if [[ "$stripped" ]]; then + echo "Stripped $binary of architectures:$stripped" + fi + STRIP_BINARY_RETVAL=1 +} + + +if [[ "$CONFIGURATION" == "Debug" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/Alamofire-watchOS/Alamofire.framework" + install_framework "${BUILT_PRODUCTS_DIR}/AlamofireObjectMapper-watchOS/AlamofireObjectMapper.framework" + install_framework "${BUILT_PRODUCTS_DIR}/CryptoSwift-watchOS/CryptoSwift.framework" + install_framework "${BUILT_PRODUCTS_DIR}/ObjectMapper-watchOS/ObjectMapper.framework" + install_framework "${BUILT_PRODUCTS_DIR}/SDWebImage-watchOS/SDWebImage.framework" +fi +if [[ "$CONFIGURATION" == "Release" ]]; then + install_framework "${BUILT_PRODUCTS_DIR}/Alamofire-watchOS/Alamofire.framework" + install_framework "${BUILT_PRODUCTS_DIR}/AlamofireObjectMapper-watchOS/AlamofireObjectMapper.framework" + install_framework "${BUILT_PRODUCTS_DIR}/CryptoSwift-watchOS/CryptoSwift.framework" + install_framework "${BUILT_PRODUCTS_DIR}/ObjectMapper-watchOS/ObjectMapper.framework" + install_framework "${BUILT_PRODUCTS_DIR}/SDWebImage-watchOS/SDWebImage.framework" +fi +if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then + wait +fi diff --git a/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-umbrella.h b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-umbrella.h new file mode 100644 index 0000000..c4b221c --- /dev/null +++ b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension-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 Pods_Watch_ExtensionVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_Watch_ExtensionVersionString[]; + diff --git a/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.debug.xcconfig b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.debug.xcconfig new file mode 100644 index 0000000..0ba399b --- /dev/null +++ b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.debug.xcconfig @@ -0,0 +1,12 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-watchOS" "${PODS_CONFIGURATION_BUILD_DIR}/AlamofireObjectMapper-watchOS" "${PODS_CONFIGURATION_BUILD_DIR}/CryptoSwift-watchOS" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-watchOS" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage-watchOS" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-watchOS/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/AlamofireObjectMapper-watchOS/AlamofireObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CryptoSwift-watchOS/CryptoSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-watchOS/ObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage-watchOS/SDWebImage.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "AlamofireObjectMapper" -framework "CryptoSwift" -framework "ImageIO" -framework "ObjectMapper" -framework "SDWebImage" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.modulemap b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.modulemap new file mode 100644 index 0000000..698175e --- /dev/null +++ b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.modulemap @@ -0,0 +1,6 @@ +framework module Pods_Watch_Extension { + umbrella header "Pods-Watch Extension-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.release.xcconfig b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.release.xcconfig new file mode 100644 index 0000000..0ba399b --- /dev/null +++ b/Pods/Target Support Files/Pods-Watch Extension/Pods-Watch Extension.release.xcconfig @@ -0,0 +1,12 @@ +ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-watchOS" "${PODS_CONFIGURATION_BUILD_DIR}/AlamofireObjectMapper-watchOS" "${PODS_CONFIGURATION_BUILD_DIR}/CryptoSwift-watchOS" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-watchOS" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage-watchOS" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire-watchOS/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/AlamofireObjectMapper-watchOS/AlamofireObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/CryptoSwift-watchOS/CryptoSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/ObjectMapper-watchOS/ObjectMapper.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage-watchOS/SDWebImage.framework/Headers" +LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' +OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "AlamofireObjectMapper" -framework "CryptoSwift" -framework "ImageIO" -framework "ObjectMapper" -framework "SDWebImage" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_PODFILE_DIR_PATH = ${SRCROOT}/. +PODS_ROOT = ${SRCROOT}/Pods +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-Info.plist b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-Info.plist new file mode 100644 index 0000000..0acad4d --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 4.4.7 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-dummy.m b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-dummy.m new file mode 100644 index 0000000..a3d951f --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_SDWebImage_iOS : NSObject +@end +@implementation PodsDummy_SDWebImage_iOS +@end diff --git a/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-prefix.pch b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-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/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-umbrella.h b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-umbrella.h new file mode 100644 index 0000000..270cd72 --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS-umbrella.h @@ -0,0 +1,44 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "NSButton+WebCache.h" +#import "NSData+ImageContentType.h" +#import "NSImage+WebCache.h" +#import "SDAnimatedImageRep.h" +#import "SDImageCache.h" +#import "SDImageCacheConfig.h" +#import "SDWebImageCoder.h" +#import "SDWebImageCoderHelper.h" +#import "SDWebImageCodersManager.h" +#import "SDWebImageCompat.h" +#import "SDWebImageDownloader.h" +#import "SDWebImageDownloaderOperation.h" +#import "SDWebImageFrame.h" +#import "SDWebImageGIFCoder.h" +#import "SDWebImageImageIOCoder.h" +#import "SDWebImageManager.h" +#import "SDWebImageOperation.h" +#import "SDWebImagePrefetcher.h" +#import "SDWebImageTransition.h" +#import "UIButton+WebCache.h" +#import "UIImage+ForceDecode.h" +#import "UIImage+GIF.h" +#import "UIImage+MemoryCacheCost.h" +#import "UIImage+MultiFormat.h" +#import "UIImageView+HighlightedWebCache.h" +#import "UIImageView+WebCache.h" +#import "UIView+WebCache.h" +#import "UIView+WebCacheOperation.h" + +FOUNDATION_EXPORT double SDWebImageVersionNumber; +FOUNDATION_EXPORT const unsigned char SDWebImageVersionString[]; + diff --git a/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS.modulemap b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS.modulemap new file mode 100644 index 0000000..1ae4c8a --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS.modulemap @@ -0,0 +1,6 @@ +framework module SDWebImage { + umbrella header "SDWebImage-iOS-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS.xcconfig b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS.xcconfig new file mode 100644 index 0000000..ec700af --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-iOS/SDWebImage-iOS.xcconfig @@ -0,0 +1,10 @@ +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage-iOS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "ImageIO" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/SDWebImage +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-Info.plist b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-Info.plist new file mode 100644 index 0000000..0acad4d --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 4.4.7 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-dummy.m b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-dummy.m new file mode 100644 index 0000000..1cedcda --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_SDWebImage_watchOS : NSObject +@end +@implementation PodsDummy_SDWebImage_watchOS +@end diff --git a/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-prefix.pch b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-prefix.pch new file mode 100644 index 0000000..e33fc32 --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-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/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-umbrella.h b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-umbrella.h new file mode 100644 index 0000000..0b8957d --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS-umbrella.h @@ -0,0 +1,44 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "NSButton+WebCache.h" +#import "NSData+ImageContentType.h" +#import "NSImage+WebCache.h" +#import "SDAnimatedImageRep.h" +#import "SDImageCache.h" +#import "SDImageCacheConfig.h" +#import "SDWebImageCoder.h" +#import "SDWebImageCoderHelper.h" +#import "SDWebImageCodersManager.h" +#import "SDWebImageCompat.h" +#import "SDWebImageDownloader.h" +#import "SDWebImageDownloaderOperation.h" +#import "SDWebImageFrame.h" +#import "SDWebImageGIFCoder.h" +#import "SDWebImageImageIOCoder.h" +#import "SDWebImageManager.h" +#import "SDWebImageOperation.h" +#import "SDWebImagePrefetcher.h" +#import "SDWebImageTransition.h" +#import "UIButton+WebCache.h" +#import "UIImage+ForceDecode.h" +#import "UIImage+GIF.h" +#import "UIImage+MemoryCacheCost.h" +#import "UIImage+MultiFormat.h" +#import "UIImageView+HighlightedWebCache.h" +#import "UIImageView+WebCache.h" +#import "UIView+WebCache.h" +#import "UIView+WebCacheOperation.h" + +FOUNDATION_EXPORT double SDWebImageVersionNumber; +FOUNDATION_EXPORT const unsigned char SDWebImageVersionString[]; + diff --git a/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS.modulemap b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS.modulemap new file mode 100644 index 0000000..c21198f --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS.modulemap @@ -0,0 +1,6 @@ +framework module SDWebImage { + umbrella header "SDWebImage-watchOS-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS.xcconfig b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS.xcconfig new file mode 100644 index 0000000..82a9c70 --- /dev/null +++ b/Pods/Target Support Files/SDWebImage-watchOS/SDWebImage-watchOS.xcconfig @@ -0,0 +1,11 @@ +APPLICATION_EXTENSION_API_ONLY = YES +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage-watchOS +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "ImageIO" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/SDWebImage +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Toast-Swift/Toast-Swift-Info.plist b/Pods/Target Support Files/Toast-Swift/Toast-Swift-Info.plist new file mode 100644 index 0000000..e2771ff --- /dev/null +++ b/Pods/Target Support Files/Toast-Swift/Toast-Swift-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.0.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/Toast-Swift/Toast-Swift-dummy.m b/Pods/Target Support Files/Toast-Swift/Toast-Swift-dummy.m new file mode 100644 index 0000000..2962aa4 --- /dev/null +++ b/Pods/Target Support Files/Toast-Swift/Toast-Swift-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_Toast_Swift : NSObject +@end +@implementation PodsDummy_Toast_Swift +@end diff --git a/Pods/Target Support Files/Toast-Swift/Toast-Swift-prefix.pch b/Pods/Target Support Files/Toast-Swift/Toast-Swift-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/Toast-Swift/Toast-Swift-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/Pods/Target Support Files/Toast-Swift/Toast-Swift-umbrella.h b/Pods/Target Support Files/Toast-Swift/Toast-Swift-umbrella.h new file mode 100644 index 0000000..8abdfa0 --- /dev/null +++ b/Pods/Target Support Files/Toast-Swift/Toast-Swift-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 Toast_SwiftVersionNumber; +FOUNDATION_EXPORT const unsigned char Toast_SwiftVersionString[]; + diff --git a/Pods/Target Support Files/Toast-Swift/Toast-Swift.modulemap b/Pods/Target Support Files/Toast-Swift/Toast-Swift.modulemap new file mode 100644 index 0000000..af3db9f --- /dev/null +++ b/Pods/Target Support Files/Toast-Swift/Toast-Swift.modulemap @@ -0,0 +1,6 @@ +framework module Toast_Swift { + umbrella header "Toast-Swift-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/Toast-Swift/Toast-Swift.xcconfig b/Pods/Target Support Files/Toast-Swift/Toast-Swift.xcconfig new file mode 100644 index 0000000..3af8e44 --- /dev/null +++ b/Pods/Target Support Files/Toast-Swift/Toast-Swift.xcconfig @@ -0,0 +1,11 @@ +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Toast-Swift +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "QuartzCore" +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}/Toast-Swift +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Toast-Swift/LICENSE b/Pods/Toast-Swift/LICENSE new file mode 100644 index 0000000..14ba7c7 --- /dev/null +++ b/Pods/Toast-Swift/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2015-2017 Charles Scalesse. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Pods/Toast-Swift/README.md b/Pods/Toast-Swift/README.md new file mode 100644 index 0000000..a99d689 --- /dev/null +++ b/Pods/Toast-Swift/README.md @@ -0,0 +1,135 @@ +Toast-Swift +============= + +[![Build Status](https://travis-ci.org/scalessec/Toast-Swift.svg?branch=master)](https://travis-ci.org/scalessec/Toast-Swift) +[![CocoaPods Version](https://img.shields.io/cocoapods/v/Toast-Swift.svg)](http://cocoadocs.org/docsets/Toast-Swift) +[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) + +Toast-Swift is a Swift extension that adds toast notifications to the `UIView` object class. It is intended to be simple, lightweight, and easy to use. Most toast notifications can be triggered with a single line of code. + +**Toast-Swift is a native Swift port of [Toast for iOS](https://github.com/scalessec/Toast "Toast for iOS").** + +Screenshots +--------- +![Toast-Swift Screenshots](toast_swift_screenshot.jpg) + + +Basic Examples +--------- +```swift +// basic usage +self.view.makeToast("This is a piece of toast") + +// toast with a specific duration and position +self.view.makeToast("This is a piece of toast", duration: 3.0, position: .top) + +// toast presented with multiple options and with a completion closure +self.view.makeToast("This is a piece of toast", duration: 2.0, point: CGPoint(x: 110.0, y: 110.0), title: "Toast Title", image: UIImage(named: "toast.png")) { didTap in + if didTap { + print("completion from tap") + } else { + print("completion without tap") + } +} + +// display toast with an activity spinner +self.view.makeToastActivity(.center) + +// display any view as toast +self.view.showToast(myView) + +// immediately hides all toast views in self.view +self.view.hideAllToasts() +``` + +But wait, there's more! +--------- +```swift +// create a new style +var style = ToastStyle() + +// this is just one of many style options +style.messageColor = .blue + +// present the toast with the new style +self.view.makeToast("This is a piece of toast", duration: 3.0, position: .bottom, style: style) + +// or perhaps you want to use this style for all toasts going forward? +// just set the shared style and there's no need to provide the style again +ToastManager.shared.style = style +self.view.makeToast("This is a piece of toast") // now uses the shared style + +// toggle "tap to dismiss" functionality +ToastManager.shared.isTapToDismissEnabled = true + +// toggle queueing behavior +ToastManager.shared.isQueueEnabled = true +``` + +See the demo project for more examples. + + +Setup Instructions +------------------ + +[CocoaPods](http://cocoapods.org) +------------------ + +To integrate Toast-Swift into your Xcode project using CocoaPods, specify it in your `Podfile`: + +```ruby +pod 'Toast-Swift', '~> 5.0.0' +``` + +and in your code add `import Toast_Swift`. + +[Carthage](https://github.com/Carthage/Carthage) +------------------ + +To integrate Toast-Swift into your Xcode project using Carthage, specify it in your `Cartfile`: + +```ogdl +github "scalessec/Toast-Swift" ~> 5.0.0 +``` + +Run `carthage update` to build the framework and drag the built `ToastSwiftFramework.framework` into your Xcode project. + +and in your code add `import ToastSwiftFramework`. + +Manually +------------------ + +1. Add `Toast.swift` to your project. +2. Grab yourself a cold 🍺. + +Compatibility +------------------ +* Version `5.x.x` requires Swift 5 and Xcode 10.2. +* Version `4.x.x` requires Swift 4.2 and Xcode 10. +* Version `3.x.x` requires Swift 4 and Xcode 9. +* Version `2.x.x` requires Swift 3 and Xcode 8. +* Version `1.4.x` requires Swift 2.2 and Xcode 7.3. +* Version `1.0.0` can be used with Swift 2.1 and earlier versions of Xcode. + +MIT License +----------- + Copyright (c) 2015-2019 Charles Scalesse. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Pods/Toast-Swift/Toast/Toast.swift b/Pods/Toast-Swift/Toast/Toast.swift new file mode 100644 index 0000000..49e64a8 --- /dev/null +++ b/Pods/Toast-Swift/Toast/Toast.swift @@ -0,0 +1,782 @@ +// +// Toast.swift +// Toast-Swift +// +// Copyright (c) 2015-2019 Charles Scalesse. +// +// 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 UIKit +import ObjectiveC + +/** + Toast is a Swift extension that adds toast notifications to the `UIView` object class. + It is intended to be simple, lightweight, and easy to use. Most toast notifications + can be triggered with a single line of code. + + The `makeToast` methods create a new view and then display it as toast. + + The `showToast` methods display any view as toast. + + */ +public extension UIView { + + /** + Keys used for associated objects. + */ + private struct ToastKeys { + static var timer = "com.toast-swift.timer" + static var duration = "com.toast-swift.duration" + static var point = "com.toast-swift.point" + static var completion = "com.toast-swift.completion" + static var activeToasts = "com.toast-swift.activeToasts" + static var activityView = "com.toast-swift.activityView" + static var queue = "com.toast-swift.queue" + } + + /** + Swift closures can't be directly associated with objects via the + Objective-C runtime, so the (ugly) solution is to wrap them in a + class that can be used with associated objects. + */ + private class ToastCompletionWrapper { + let completion: ((Bool) -> Void)? + + init(_ completion: ((Bool) -> Void)?) { + self.completion = completion + } + } + + private enum ToastError: Error { + case missingParameters + } + + private var activeToasts: NSMutableArray { + get { + if let activeToasts = objc_getAssociatedObject(self, &ToastKeys.activeToasts) as? NSMutableArray { + return activeToasts + } else { + let activeToasts = NSMutableArray() + objc_setAssociatedObject(self, &ToastKeys.activeToasts, activeToasts, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + return activeToasts + } + } + } + + private var queue: NSMutableArray { + get { + if let queue = objc_getAssociatedObject(self, &ToastKeys.queue) as? NSMutableArray { + return queue + } else { + let queue = NSMutableArray() + objc_setAssociatedObject(self, &ToastKeys.queue, queue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + return queue + } + } + } + + // MARK: - Make Toast Methods + + /** + Creates and presents a new toast view. + + @param message The message to be displayed + @param duration The toast duration + @param position The toast's position + @param title The title + @param image The image + @param style The style. The shared style will be used when nil + @param completion The completion closure, executed after the toast view disappears. + didTap will be `true` if the toast view was dismissed from a tap. + */ + func makeToast(_ message: String?, duration: TimeInterval = ToastManager.shared.duration, position: ToastPosition = ToastManager.shared.position, title: String? = nil, image: UIImage? = nil, style: ToastStyle = ToastManager.shared.style, completion: ((_ didTap: Bool) -> Void)? = nil) { + do { + let toast = try toastViewForMessage(message, title: title, image: image, style: style) + showToast(toast, duration: duration, position: position, completion: completion) + } catch ToastError.missingParameters { + print("Error: message, title, and image are all nil") + } catch {} + } + + /** + Creates a new toast view and presents it at a given center point. + + @param message The message to be displayed + @param duration The toast duration + @param point The toast's center point + @param title The title + @param image The image + @param style The style. The shared style will be used when nil + @param completion The completion closure, executed after the toast view disappears. + didTap will be `true` if the toast view was dismissed from a tap. + */ + func makeToast(_ message: String?, duration: TimeInterval = ToastManager.shared.duration, point: CGPoint, title: String?, image: UIImage?, style: ToastStyle = ToastManager.shared.style, completion: ((_ didTap: Bool) -> Void)?) { + do { + let toast = try toastViewForMessage(message, title: title, image: image, style: style) + showToast(toast, duration: duration, point: point, completion: completion) + } catch ToastError.missingParameters { + print("Error: message, title, and image cannot all be nil") + } catch {} + } + + // MARK: - Show Toast Methods + + /** + Displays any view as toast at a provided position and duration. The completion closure + executes when the toast view completes. `didTap` will be `true` if the toast view was + dismissed from a tap. + + @param toast The view to be displayed as toast + @param duration The notification duration + @param position The toast's position + @param completion The completion block, executed after the toast view disappears. + didTap will be `true` if the toast view was dismissed from a tap. + */ + func showToast(_ toast: UIView, duration: TimeInterval = ToastManager.shared.duration, position: ToastPosition = ToastManager.shared.position, completion: ((_ didTap: Bool) -> Void)? = nil) { + let point = position.centerPoint(forToast: toast, inSuperview: self) + showToast(toast, duration: duration, point: point, completion: completion) + } + + /** + Displays any view as toast at a provided center point and duration. The completion closure + executes when the toast view completes. `didTap` will be `true` if the toast view was + dismissed from a tap. + + @param toast The view to be displayed as toast + @param duration The notification duration + @param point The toast's center point + @param completion The completion block, executed after the toast view disappears. + didTap will be `true` if the toast view was dismissed from a tap. + */ + func showToast(_ toast: UIView, duration: TimeInterval = ToastManager.shared.duration, point: CGPoint, completion: ((_ didTap: Bool) -> Void)? = nil) { + objc_setAssociatedObject(toast, &ToastKeys.completion, ToastCompletionWrapper(completion), .OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + if ToastManager.shared.isQueueEnabled, activeToasts.count > 0 { + objc_setAssociatedObject(toast, &ToastKeys.duration, NSNumber(value: duration), .OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(toast, &ToastKeys.point, NSValue(cgPoint: point), .OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + queue.add(toast) + } else { + showToast(toast, duration: duration, point: point) + } + } + + // MARK: - Hide Toast Methods + + /** + Hides the active toast. If there are multiple toasts active in a view, this method + hides the oldest toast (the first of the toasts to have been presented). + + @see `hideAllToasts()` to remove all active toasts from a view. + + @warning This method has no effect on activity toasts. Use `hideToastActivity` to + hide activity toasts. + + */ + func hideToast() { + guard let activeToast = activeToasts.firstObject as? UIView else { return } + hideToast(activeToast) + } + + /** + Hides an active toast. + + @param toast The active toast view to dismiss. Any toast that is currently being displayed + on the screen is considered active. + + @warning this does not clear a toast view that is currently waiting in the queue. + */ + func hideToast(_ toast: UIView) { + guard activeToasts.contains(toast) else { return } + hideToast(toast, fromTap: false) + } + + /** + Hides all toast views. + + @param includeActivity If `true`, toast activity will also be hidden. Default is `false`. + @param clearQueue If `true`, removes all toast views from the queue. Default is `true`. + */ + func hideAllToasts(includeActivity: Bool = false, clearQueue: Bool = true) { + if clearQueue { + clearToastQueue() + } + + activeToasts.compactMap { $0 as? UIView } + .forEach { hideToast($0) } + + if includeActivity { + hideToastActivity() + } + } + + /** + Removes all toast views from the queue. This has no effect on toast views that are + active. Use `hideAllToasts(clearQueue:)` to hide the active toasts views and clear + the queue. + */ + func clearToastQueue() { + queue.removeAllObjects() + } + + // MARK: - Activity Methods + + /** + Creates and displays a new toast activity indicator view at a specified position. + + @warning Only one toast activity indicator view can be presented per superview. Subsequent + calls to `makeToastActivity(position:)` will be ignored until `hideToastActivity()` is called. + + @warning `makeToastActivity(position:)` works independently of the `showToast` methods. Toast + activity views can be presented and dismissed while toast views are being displayed. + `makeToastActivity(position:)` has no effect on the queueing behavior of the `showToast` methods. + + @param position The toast's position + */ + func makeToastActivity(_ position: ToastPosition) { + // sanity + guard objc_getAssociatedObject(self, &ToastKeys.activityView) as? UIView == nil else { return } + + let toast = createToastActivityView() + let point = position.centerPoint(forToast: toast, inSuperview: self) + makeToastActivity(toast, point: point) + } + + /** + Creates and displays a new toast activity indicator view at a specified position. + + @warning Only one toast activity indicator view can be presented per superview. Subsequent + calls to `makeToastActivity(position:)` will be ignored until `hideToastActivity()` is called. + + @warning `makeToastActivity(position:)` works independently of the `showToast` methods. Toast + activity views can be presented and dismissed while toast views are being displayed. + `makeToastActivity(position:)` has no effect on the queueing behavior of the `showToast` methods. + + @param point The toast's center point + */ + func makeToastActivity(_ point: CGPoint) { + // sanity + guard objc_getAssociatedObject(self, &ToastKeys.activityView) as? UIView == nil else { return } + + let toast = createToastActivityView() + makeToastActivity(toast, point: point) + } + + /** + Dismisses the active toast activity indicator view. + */ + func hideToastActivity() { + if let toast = objc_getAssociatedObject(self, &ToastKeys.activityView) as? UIView { + UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseIn, .beginFromCurrentState], animations: { + toast.alpha = 0.0 + }) { _ in + toast.removeFromSuperview() + objc_setAssociatedObject(self, &ToastKeys.activityView, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + } + + // MARK: - Private Activity Methods + + private func makeToastActivity(_ toast: UIView, point: CGPoint) { + toast.alpha = 0.0 + toast.center = point + + objc_setAssociatedObject(self, &ToastKeys.activityView, toast, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + + self.addSubview(toast) + + UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: .curveEaseOut, animations: { + toast.alpha = 1.0 + }) + } + + private func createToastActivityView() -> UIView { + let style = ToastManager.shared.style + + let activityView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: style.activitySize.width, height: style.activitySize.height)) + activityView.backgroundColor = style.activityBackgroundColor + activityView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin] + activityView.layer.cornerRadius = style.cornerRadius + + if style.displayShadow { + activityView.layer.shadowColor = style.shadowColor.cgColor + activityView.layer.shadowOpacity = style.shadowOpacity + activityView.layer.shadowRadius = style.shadowRadius + activityView.layer.shadowOffset = style.shadowOffset + } + + let activityIndicatorView = UIActivityIndicatorView(style: .whiteLarge) + activityIndicatorView.center = CGPoint(x: activityView.bounds.size.width / 2.0, y: activityView.bounds.size.height / 2.0) + activityView.addSubview(activityIndicatorView) + activityIndicatorView.color = style.activityIndicatorColor + activityIndicatorView.startAnimating() + + return activityView + } + + // MARK: - Private Show/Hide Methods + + private func showToast(_ toast: UIView, duration: TimeInterval, point: CGPoint) { + toast.center = point + toast.alpha = 0.0 + + if ToastManager.shared.isTapToDismissEnabled { + let recognizer = UITapGestureRecognizer(target: self, action: #selector(UIView.handleToastTapped(_:))) + toast.addGestureRecognizer(recognizer) + toast.isUserInteractionEnabled = true + toast.isExclusiveTouch = true + } + + activeToasts.add(toast) + self.addSubview(toast) + + UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseOut, .allowUserInteraction], animations: { + toast.alpha = 1.0 + }) { _ in + let timer = Timer(timeInterval: duration, target: self, selector: #selector(UIView.toastTimerDidFinish(_:)), userInfo: toast, repeats: false) + RunLoop.main.add(timer, forMode: .common) + objc_setAssociatedObject(toast, &ToastKeys.timer, timer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) + } + } + + private func hideToast(_ toast: UIView, fromTap: Bool) { + if let timer = objc_getAssociatedObject(toast, &ToastKeys.timer) as? Timer { + timer.invalidate() + } + + UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseIn, .beginFromCurrentState], animations: { + toast.alpha = 0.0 + }) { _ in + toast.removeFromSuperview() + self.activeToasts.remove(toast) + + if let wrapper = objc_getAssociatedObject(toast, &ToastKeys.completion) as? ToastCompletionWrapper, let completion = wrapper.completion { + completion(fromTap) + } + + if let nextToast = self.queue.firstObject as? UIView, let duration = objc_getAssociatedObject(nextToast, &ToastKeys.duration) as? NSNumber, let point = objc_getAssociatedObject(nextToast, &ToastKeys.point) as? NSValue { + self.queue.removeObject(at: 0) + self.showToast(nextToast, duration: duration.doubleValue, point: point.cgPointValue) + } + } + } + + // MARK: - Events + + @objc + private func handleToastTapped(_ recognizer: UITapGestureRecognizer) { + guard let toast = recognizer.view else { return } + hideToast(toast, fromTap: true) + } + + @objc + private func toastTimerDidFinish(_ timer: Timer) { + guard let toast = timer.userInfo as? UIView else { return } + hideToast(toast) + } + + // MARK: - Toast Construction + + /** + Creates a new toast view with any combination of message, title, and image. + The look and feel is configured via the style. Unlike the `makeToast` methods, + this method does not present the toast view automatically. One of the `showToast` + methods must be used to present the resulting view. + + @warning if message, title, and image are all nil, this method will throw + `ToastError.missingParameters` + + @param message The message to be displayed + @param title The title + @param image The image + @param style The style. The shared style will be used when nil + @throws `ToastError.missingParameters` when message, title, and image are all nil + @return The newly created toast view + */ + func toastViewForMessage(_ message: String?, title: String?, image: UIImage?, style: ToastStyle) throws -> UIView { + // sanity + guard message != nil || title != nil || image != nil else { + throw ToastError.missingParameters + } + + var messageLabel: UILabel? + var titleLabel: UILabel? + var imageView: UIImageView? + + let wrapperView = UIView() + wrapperView.backgroundColor = style.backgroundColor + wrapperView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin] + wrapperView.layer.cornerRadius = style.cornerRadius + + if style.displayShadow { + wrapperView.layer.shadowColor = UIColor.black.cgColor + wrapperView.layer.shadowOpacity = style.shadowOpacity + wrapperView.layer.shadowRadius = style.shadowRadius + wrapperView.layer.shadowOffset = style.shadowOffset + } + + if let image = image { + imageView = UIImageView(image: image) + imageView?.contentMode = .scaleAspectFit + imageView?.frame = CGRect(x: style.horizontalPadding, y: style.verticalPadding, width: style.imageSize.width, height: style.imageSize.height) + } + + var imageRect = CGRect.zero + + if let imageView = imageView { + imageRect.origin.x = style.horizontalPadding + imageRect.origin.y = style.verticalPadding + imageRect.size.width = imageView.bounds.size.width + imageRect.size.height = imageView.bounds.size.height + } + + if let title = title { + titleLabel = UILabel() + titleLabel?.numberOfLines = style.titleNumberOfLines + titleLabel?.font = style.titleFont + titleLabel?.textAlignment = style.titleAlignment + titleLabel?.lineBreakMode = .byTruncatingTail + titleLabel?.textColor = style.titleColor + titleLabel?.backgroundColor = UIColor.clear + titleLabel?.text = title; + + let maxTitleSize = CGSize(width: (self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, height: self.bounds.size.height * style.maxHeightPercentage) + let titleSize = titleLabel?.sizeThatFits(maxTitleSize) + if let titleSize = titleSize { + titleLabel?.frame = CGRect(x: 0.0, y: 0.0, width: titleSize.width, height: titleSize.height) + } + } + + if let message = message { + messageLabel = UILabel() + messageLabel?.text = message + messageLabel?.numberOfLines = style.messageNumberOfLines + messageLabel?.font = style.messageFont + messageLabel?.textAlignment = style.messageAlignment + messageLabel?.lineBreakMode = .byTruncatingTail; + messageLabel?.textColor = style.messageColor + messageLabel?.backgroundColor = UIColor.clear + + let maxMessageSize = CGSize(width: (self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, height: self.bounds.size.height * style.maxHeightPercentage) + let messageSize = messageLabel?.sizeThatFits(maxMessageSize) + if let messageSize = messageSize { + let actualWidth = min(messageSize.width, maxMessageSize.width) + let actualHeight = min(messageSize.height, maxMessageSize.height) + messageLabel?.frame = CGRect(x: 0.0, y: 0.0, width: actualWidth, height: actualHeight) + } + } + + var titleRect = CGRect.zero + + if let titleLabel = titleLabel { + titleRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding + titleRect.origin.y = style.verticalPadding + titleRect.size.width = titleLabel.bounds.size.width + titleRect.size.height = titleLabel.bounds.size.height + } + + var messageRect = CGRect.zero + + if let messageLabel = messageLabel { + messageRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding + messageRect.origin.y = titleRect.origin.y + titleRect.size.height + style.verticalPadding + messageRect.size.width = messageLabel.bounds.size.width + messageRect.size.height = messageLabel.bounds.size.height + } + + let longerWidth = max(titleRect.size.width, messageRect.size.width) + let longerX = max(titleRect.origin.x, messageRect.origin.x) + let wrapperWidth = max((imageRect.size.width + (style.horizontalPadding * 2.0)), (longerX + longerWidth + style.horizontalPadding)) + let wrapperHeight = max((messageRect.origin.y + messageRect.size.height + style.verticalPadding), (imageRect.size.height + (style.verticalPadding * 2.0))) + + wrapperView.frame = CGRect(x: 0.0, y: 0.0, width: wrapperWidth, height: wrapperHeight) + + if let titleLabel = titleLabel { + titleRect.size.width = longerWidth + titleLabel.frame = titleRect + wrapperView.addSubview(titleLabel) + } + + if let messageLabel = messageLabel { + messageRect.size.width = longerWidth + messageLabel.frame = messageRect + wrapperView.addSubview(messageLabel) + } + + if let imageView = imageView { + wrapperView.addSubview(imageView) + } + + return wrapperView + } + +} + +// MARK: - Toast Style + +/** + `ToastStyle` instances define the look and feel for toast views created via the + `makeToast` methods as well for toast views created directly with + `toastViewForMessage(message:title:image:style:)`. + + @warning `ToastStyle` offers relatively simple styling options for the default + toast view. If you require a toast view with more complex UI, it probably makes more + sense to create your own custom UIView subclass and present it with the `showToast` + methods. +*/ +public struct ToastStyle { + + public init() {} + + /** + The background color. Default is `.black` at 80% opacity. + */ + public var backgroundColor: UIColor = UIColor.black.withAlphaComponent(0.8) + + /** + The title color. Default is `UIColor.whiteColor()`. + */ + public var titleColor: UIColor = .white + + /** + The message color. Default is `.white`. + */ + public var messageColor: UIColor = .white + + /** + A percentage value from 0.0 to 1.0, representing the maximum width of the toast + view relative to it's superview. Default is 0.8 (80% of the superview's width). + */ + public var maxWidthPercentage: CGFloat = 0.8 { + didSet { + maxWidthPercentage = max(min(maxWidthPercentage, 1.0), 0.0) + } + } + + /** + A percentage value from 0.0 to 1.0, representing the maximum height of the toast + view relative to it's superview. Default is 0.8 (80% of the superview's height). + */ + public var maxHeightPercentage: CGFloat = 0.8 { + didSet { + maxHeightPercentage = max(min(maxHeightPercentage, 1.0), 0.0) + } + } + + /** + The spacing from the horizontal edge of the toast view to the content. When an image + is present, this is also used as the padding between the image and the text. + Default is 10.0. + + */ + public var horizontalPadding: CGFloat = 10.0 + + /** + The spacing from the vertical edge of the toast view to the content. When a title + is present, this is also used as the padding between the title and the message. + Default is 10.0. On iOS11+, this value is added added to the `safeAreaInset.top` + and `safeAreaInsets.bottom`. + */ + public var verticalPadding: CGFloat = 10.0 + + /** + The corner radius. Default is 10.0. + */ + public var cornerRadius: CGFloat = 10.0; + + /** + The title font. Default is `.boldSystemFont(16.0)`. + */ + public var titleFont: UIFont = .boldSystemFont(ofSize: 16.0) + + /** + The message font. Default is `.systemFont(ofSize: 16.0)`. + */ + public var messageFont: UIFont = .systemFont(ofSize: 16.0) + + /** + The title text alignment. Default is `NSTextAlignment.Left`. + */ + public var titleAlignment: NSTextAlignment = .left + + /** + The message text alignment. Default is `NSTextAlignment.Left`. + */ + public var messageAlignment: NSTextAlignment = .left + + /** + The maximum number of lines for the title. The default is 0 (no limit). + */ + public var titleNumberOfLines = 0 + + /** + The maximum number of lines for the message. The default is 0 (no limit). + */ + public var messageNumberOfLines = 0 + + /** + Enable or disable a shadow on the toast view. Default is `false`. + */ + public var displayShadow = false + + /** + The shadow color. Default is `.black`. + */ + public var shadowColor: UIColor = .black + + /** + A value from 0.0 to 1.0, representing the opacity of the shadow. + Default is 0.8 (80% opacity). + */ + public var shadowOpacity: Float = 0.8 { + didSet { + shadowOpacity = max(min(shadowOpacity, 1.0), 0.0) + } + } + + /** + The shadow radius. Default is 6.0. + */ + public var shadowRadius: CGFloat = 6.0 + + /** + The shadow offset. The default is 4 x 4. + */ + public var shadowOffset = CGSize(width: 4.0, height: 4.0) + + /** + The image size. The default is 80 x 80. + */ + public var imageSize = CGSize(width: 80.0, height: 80.0) + + /** + The size of the toast activity view when `makeToastActivity(position:)` is called. + Default is 100 x 100. + */ + public var activitySize = CGSize(width: 100.0, height: 100.0) + + /** + The fade in/out animation duration. Default is 0.2. + */ + public var fadeDuration: TimeInterval = 0.2 + + /** + Activity indicator color. Default is `.white`. + */ + public var activityIndicatorColor: UIColor = .white + + /** + Activity background color. Default is `.black` at 80% opacity. + */ + public var activityBackgroundColor: UIColor = UIColor.black.withAlphaComponent(0.8) + +} + +// MARK: - Toast Manager + +/** + `ToastManager` provides general configuration options for all toast + notifications. Backed by a singleton instance. +*/ +public class ToastManager { + + /** + The `ToastManager` singleton instance. + + */ + public static let shared = ToastManager() + + /** + The shared style. Used whenever toastViewForMessage(message:title:image:style:) is called + with with a nil style. + + */ + public var style = ToastStyle() + + /** + Enables or disables tap to dismiss on toast views. Default is `true`. + + */ + public var isTapToDismissEnabled = true + + /** + Enables or disables queueing behavior for toast views. When `true`, + toast views will appear one after the other. When `false`, multiple toast + views will appear at the same time (potentially overlapping depending + on their positions). This has no effect on the toast activity view, + which operates independently of normal toast views. Default is `false`. + + */ + public var isQueueEnabled = false + + /** + The default duration. Used for the `makeToast` and + `showToast` methods that don't require an explicit duration. + Default is 3.0. + + */ + public var duration: TimeInterval = 3.0 + + /** + Sets the default position. Used for the `makeToast` and + `showToast` methods that don't require an explicit position. + Default is `ToastPosition.Bottom`. + + */ + public var position: ToastPosition = .bottom + +} + +// MARK: - ToastPosition + +public enum ToastPosition { + case top + case center + case bottom + + fileprivate func centerPoint(forToast toast: UIView, inSuperview superview: UIView) -> CGPoint { + let topPadding: CGFloat = ToastManager.shared.style.verticalPadding + superview.csSafeAreaInsets.top + let bottomPadding: CGFloat = ToastManager.shared.style.verticalPadding + superview.csSafeAreaInsets.bottom + + switch self { + case .top: + return CGPoint(x: superview.bounds.size.width / 2.0, y: (toast.frame.size.height / 2.0) + topPadding) + case .center: + return CGPoint(x: superview.bounds.size.width / 2.0, y: superview.bounds.size.height / 2.0) + case .bottom: + return CGPoint(x: superview.bounds.size.width / 2.0, y: (superview.bounds.size.height - (toast.frame.size.height / 2.0)) - bottomPadding) + } + } +} + +// MARK: - Private UIView Extensions + +private extension UIView { + + var csSafeAreaInsets: UIEdgeInsets { + if #available(iOS 11.0, *) { + return self.safeAreaInsets + } else { + return .zero + } + } + +}